From e84a621ea70f8bf187bb42896ba8b7b8df49c0ae Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 26 Jul 2023 00:10:46 -0400 Subject: [PATCH 001/717] Migrate to .NET 8 Preview - Update Nuget packages to preview - Update documentation refs - Update CI dotnet version - Update redistributable - Update winget and deb dependencies - Update base docker images - Remove unnecessary console `PropertyGroup`s - Modify CI to be ODR for the dotnet version - Fix upgrade `#error`s - Http2 never worked and now throws a warning. Remove it - Remove workaround for SqlClient breaking change - Minor return signature optimization in ProcessExecutor - Config version -> 5.0.0 - Core version -> 6.0.0 --- .github/CONTRIBUTING.md | 2 +- .github/workflows/ci-pipeline.yml | 28 +++++++-------- README.md | 8 ++--- build/Dockerfile | 4 +-- build/Version.props | 8 ++--- build/package/deb/build_package.sh | 2 +- build/package/deb/debian/control | 4 +-- .../manifest/Tgstation.Server.installer.yaml | 2 +- .../Tgstation.Server.Host.Console.csproj | 13 +------ .../Tgstation.Server.Host.Service.csproj | 8 ++--- .../Tgstation.Server.Host.Watchdog.csproj | 2 +- .../Watchdog.cs | 2 +- .../Components/README.md | 2 +- .../Database/SqlServerDatabaseContext.cs | 18 +--------- .../IO/DefaultIOManager.cs | 4 +-- src/Tgstation.Server.Host/README.md | 4 +-- src/Tgstation.Server.Host/ServerFactory.cs | 4 +-- .../Setup/SetupWizard.cs | 7 ++-- .../System/ProcessExecutor.cs | 15 ++++---- .../System/SystemDManager.cs | 2 +- .../Tgstation.Server.Host.csproj | 20 +++++------ src/Tgstation.Server.Host/Utils/README.md | 2 +- .../Setup/TestSetupWizard.cs | 2 ++ .../Utils/TestAsyncDelayer.cs | 4 +-- tools/Tgstation.Server.Migrator/Program.cs | 14 ++++---- .../RuntimeDistributableAttribute.cs | 34 +++++++++++++++++++ .../Tgstation.Server.Migrator.csproj | 17 ++++++++-- 27 files changed, 126 insertions(+), 106 deletions(-) create mode 100644 tools/Tgstation.Server.Migrator/Properties/RuntimeDistributableAttribute.cs diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index d8b62ead678..2cedb62bfdb 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -34,7 +34,7 @@ You can of course, as always, ask for help at [#coderbus](irc://irc.rizon.net/co ### Development Environment -You need the .NET 6.0 SDK and npm>=v5.7 (in your PATH) to compile the server. +You need the .NET 8.0 SDK and npm>=v5.7 (in your PATH) to compile the server. The recommended IDE is Visual Studio 2022 or VSCode. diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index c6b420c33c0..4428c8d513b 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -38,7 +38,7 @@ on: - V6 env: - TGS_DOTNET_VERSION: 6.0.x + TGS_DOTNET_VERSION: 8.0.x TGS_TEST_GITHUB_TOKEN: ${{ secrets.LIVE_TESTS_TOKEN }} TGS_RELEASE_NOTES_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} WINGET_PUSH_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} @@ -246,7 +246,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v2 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' - name: Checkout (Branch) uses: actions/checkout@v3 @@ -289,7 +289,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v2 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' - name: Checkout (Branch) uses: actions/checkout@v3 @@ -338,7 +338,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v2 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' - name: Set TGS_TEST_DUMP_API_SPEC if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'System' && matrix.database-type == 'SqlServer' }} @@ -534,7 +534,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v2 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' - name: Set Sqlite Connection Info if: ${{ matrix.database-type == 'Sqlite' }} @@ -933,15 +933,15 @@ jobs: echo ${{ secrets.PACKAGING_PRIVATE_KEY_PASSPHRASE }} | gpg --batch --yes --passphrase-fd 0 --import private.pgp rm private.pgp - - name: Install dotnet-sdk-6.0 + - name: Install dotnet-sdk system package run: | sudo apt-get update - sudo apt-get install -y dotnet-sdk-6.0 + sudo apt-get install -y dotnet-sdk-${{ env.TGS_DOTNET_VERSION }} - name: Setup dotnet uses: actions/setup-dotnet@v2 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' - name: Override /usr/bin/dotnet run: | @@ -1027,7 +1027,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v2 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' - name: Checkout (Branch) uses: actions/checkout@v3 @@ -1152,7 +1152,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v2 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' - name: Retrieve Latest winget-pkgs PULL_REQUEST_TEMPLATE commit SHA from GitHub API id: get-sha @@ -1291,7 +1291,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v2 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' - name: Checkout uses: actions/checkout@v3 @@ -1329,7 +1329,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v2 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' - name: Checkout uses: actions/checkout@v3 @@ -1352,7 +1352,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v2 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' - name: Checkout uses: actions/checkout@v3 @@ -1590,7 +1590,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v2 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' - name: Install winget uses: Cyberboss/install-winget@v1 diff --git a/README.md b/README.md index ab758a5b364..63215614b9c 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ Note: The `winget` package is submitted to Microsoft for approval once TGS relea ##### Manual -If you don't have it installed already, download and install the [ASP .NET Core Runtime Hosting Bundle (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. +If you don't have it installed already, download and install the [ASP .NET Core Runtime Hosting Bundle (>= v8.0)](https://dotnet.microsoft.com/download/dotnet/8.0). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). You can test this by opening a command prompt and running `dotnet --list-runtimes`. [Download the latest release .zip](https://github.com/tgstation/tgstation-server/releases/latest). Typically, you want the `ServerService.zip` package in order to run TGS as a Windows service. Choose `ServerConsole.zip` if you prefer to use a command line daemon. @@ -119,7 +119,7 @@ sudo dpkg --add-architecture i386 \ ##### Debian -The `aspnetcore-runtime-6.0` package isn't yet available on mainline Debian and must be [installed from Microsoft](https://learn.microsoft.com/en-us/dotnet/core/install/linux-debian) first. Use the following one-liner to add their packages repository. +The `aspnetcore-runtime-8.0` package isn't yet available on mainline Debian and must be [installed from Microsoft](https://learn.microsoft.com/en-us/dotnet/core/install/linux-debian) first. Use the following one-liner to add their packages repository. ```sh curl -L https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -o packages-microsoft-prod.deb \ @@ -135,7 +135,7 @@ _Support for more distros coming soon_ The following dependencies are required. -- aspnetcore-runtime-6.0 (Note, not all supported distros have this package, see the links above for official Microsoft installation instructions) +- aspnetcore-runtime-8.0 (Note, not all supported distros have this package, see the links above for official Microsoft installation instructions) - libc6-i386 - libstdc++6:i386 - gcc-multilib (Only on 64-bit systems) @@ -197,7 +197,7 @@ There are 3 primary supported ways to configure TGS: - Set environment variables in the form `Section__Subsection=value` or `Section__ArraySubsection__0=value` for arrays. - Set command line arguments in the form `--Section:Subsection=value` or `--Section:ArraySubsection:0=value` for arrays. -The latter two are not recommended as they cannot be dynamically changed at runtime. See more on ASP.NET core configuration [here](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0). +The latter two are not recommended as they cannot be dynamically changed at runtime. See more on ASP.NET core configuration [here](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-8.0). #### Manual Configuration diff --git a/build/Dockerfile b/build/Dockerfile index f1f70e95b3f..7985eb8c9ac 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0-bookworm-slim AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim AS build # install node and npm # replace shell with bash so we can source files @@ -63,7 +63,7 @@ RUN dotnet publish -c Release -o /app WORKDIR /repo/src/Tgstation.Server.Host RUN dotnet publish -c Release -o /app/lib/Default && mv /app/lib/Default/appsettings* /app -FROM mcr.microsoft.com/dotnet/aspnet:6.0-bookworm-slim +FROM mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim #needed for byond RUN apt-get update \ diff --git a/build/Version.props b/build/Version.props index 9a9b414cfe4..d1fc8f38c31 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,8 +3,8 @@ - 5.14.0 - 4.7.1 + 6.0.0 + 5.0.0 9.11.0 6.0.0 11.0.0 @@ -15,9 +15,9 @@ 1.2.1 1.0.2 netstandard2.0 - 6 + 8 - https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/6.0.20/dotnet-hosting-6.0.20-win.exe + https://download.visualstudio.microsoft.com/download/pr/e5db48f5-99c6-42ca-804a-85b89ae09671/b5594181b347a9a77246e3645916bd0e/dotnet-hosting-8.0.0-preview.6.23329.11-win.exe 11.0.2 https://ftp.osuosl.org/pub/mariadb/mariadb-11.0.2/winx64-packages/mariadb-11.0.2-winx64.msi diff --git a/build/package/deb/build_package.sh b/build/package/deb/build_package.sh index 54063487dc4..2f81abb1e01 100755 --- a/build/package/deb/build_package.sh +++ b/build/package/deb/build_package.sh @@ -8,7 +8,7 @@ set -x dpkg --add-architecture i386 apt-get update -apt-get install -y npm dotnet-sdk-6.0 build-essential binutils lintian debhelper dh-make devscripts xmlstarlet # needs cleanup probably, SO copypasta +apt-get install -y npm dotnet-sdk-8.0 build-essential binutils lintian debhelper dh-make devscripts xmlstarlet # needs cleanup probably, SO copypasta CURRENT_COMMIT=$(git rev-parse HEAD) diff --git a/build/package/deb/debian/control b/build/package/deb/debian/control index a4e47829c70..ee30543ecf4 100644 --- a/build/package/deb/debian/control +++ b/build/package/deb/debian/control @@ -5,7 +5,7 @@ Maintainer: Jordan Dominion Rules-Requires-Root: no Build-Depends: debhelper-compat (= 13), - dotnet-sdk-6.0, + dotnet-sdk-8.0, npm, Standards-Version: 4.6.2 Homepage: https://tgstation.github.io/tgstation-server @@ -16,7 +16,7 @@ Package: tgstation-server Architecture: any Depends: ${misc:Depends}, - aspnetcore-runtime-6.0, + aspnetcore-runtime-8.0, libc6-i386, libstdc++6:i386 [amd64], libstdc++6 [i386], diff --git a/build/package/winget/manifest/Tgstation.Server.installer.yaml b/build/package/winget/manifest/Tgstation.Server.installer.yaml index f160b697837..7aa187b1bf9 100644 --- a/build/package/winget/manifest/Tgstation.Server.installer.yaml +++ b/build/package/winget/manifest/Tgstation.Server.installer.yaml @@ -25,7 +25,7 @@ Installers: Publisher: /tg/station 13 Dependencies: PackageDependencies: - - PackageIdentifier: Microsoft.DotNet.HostingBundle.6 + - PackageIdentifier: Microsoft.DotNet.HostingBundle.8 ReleaseDate: 2023-06-24 # Do not change. Set before publish by push_manifest.ps1 ManifestType: installer ManifestVersion: 1.4.0 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 7a85df7ea40..ebe2348e40d 100644 --- a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj +++ b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj @@ -9,20 +9,9 @@ ../../build/uac_elevation_manifest.xml - - true - - bin\Release\net6.0\Tgstation.Server.Host.Console.xml - - - - 1701;1702;SA1652 - bin\Debug\net6.0\Tgstation.Server.Host.Console.xml - - - + 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 0186298b281..1e102db9959 100644 --- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj +++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj @@ -19,15 +19,15 @@ - + - + - + - + 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 4cda1e51b14..bfd4955b3bb 100644 --- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj +++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index 21d60f52031..02b25a0726e 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -82,7 +82,7 @@ public async Task RunAsync(bool runConfigure, string[] args, CancellationT Directory.Delete(assemblyStoragePath, true); Directory.CreateDirectory(defaultAssemblyPath); - var sourcePath = "../../../../Tgstation.Server.Host/bin/Debug/net6.0"; + var sourcePath = "../../../../Tgstation.Server.Host/bin/Debug/net8.0"; foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories)) Directory.CreateDirectory(dirPath.Replace(sourcePath, defaultAssemblyPath, StringComparison.Ordinal)); diff --git a/src/Tgstation.Server.Host/Components/README.md b/src/Tgstation.Server.Host/Components/README.md index e13f2a3dfbc..2106f47dd7a 100644 --- a/src/Tgstation.Server.Host/Components/README.md +++ b/src/Tgstation.Server.Host/Components/README.md @@ -20,4 +20,4 @@ While the database represents stored instance data, in component code an instanc `IInstance`s ([implementation](./Instance.cs)) are created via the [IInstanceFactory](./IInstanceFactory.cs) ([implementation](./InstanceFactory.cs)) and are generally controlled via the [IInstanceOperations](./IInstanceOperations.cs) interface (implemented in the `InstanceManager`). -Many classes in here implement [IHostedService](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-6.0&tabs=visual-studio), `InstanceManager` being the only one that is called by the ASP.NET runtime. In the case of instances `StartAsync()` is called when an `Instance` is being brought online (from server startup or user request). The `Instance` handles calling `StartAsync()` on its various subcomponents that need it. When an `Instance` is being brought offline (from server shutdown/restart/update or user request) the same pattern is followed calling `StopAsync()`. +Many classes in here implement [IHostedService](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-8.0&tabs=visual-studio), `InstanceManager` being the only one that is called by the ASP.NET runtime. In the case of instances `StartAsync()` is called when an `Instance` is being brought online (from server startup or user request). The `Instance` handles calling `StartAsync()` on its various subcomponents that need it. When an `Instance` is being brought offline (from server shutdown/restart/update or user request) the same pattern is followed calling `StopAsync()`. diff --git a/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs b/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs index 33cab94dcfa..4402b956b95 100644 --- a/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs @@ -34,24 +34,8 @@ public static void ConfigureWith(DbContextOptionsBuilder options, DatabaseConfig if (databaseConfiguration.DatabaseType != DatabaseType.SqlServer) throw new InvalidOperationException($"Invalid DatabaseType for {nameof(SqlServerDatabaseContext)}!"); -#if NET7_0_OR_GREATER -#error Perform this breaking config change -#endif - - // Workaround for breaking change https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-7.0/breaking-changes#encrypt-true - var connectionString = databaseConfiguration.ConnectionString; - if (!connectionString.Contains("Encrypt=", StringComparison.OrdinalIgnoreCase)) - { - var connectionStringBuilder = new SqlConnectionStringBuilder(databaseConfiguration.ConnectionString) - { - Encrypt = false, - }; - - connectionString = connectionStringBuilder.ToString(); - } - options.UseSqlServer( - connectionString, + databaseConfiguration.ConnectionString, sqlServerOptions => { sqlServerOptions.EnableRetryOnFailure(); diff --git a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs index 23d36cafd59..ca3ba2cd28b 100644 --- a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs +++ b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs @@ -284,8 +284,8 @@ public Task ZipToDirectory(string path, Stream zipFile, CancellationToken cancel path = ResolvePath(path); ArgumentNullException.ThrowIfNull(zipFile); -#if NET7_0_OR_GREATER -#warning Check if zip file seeking has been addressesed. See https://github.com/tgstation/tgstation-server/issues/1531 +#if NET9_0_OR_GREATER +#error Check if zip file seeking has been addressesed. See https://github.com/tgstation/tgstation-server/issues/1531 #endif // ZipArchive does a synchronous copy on unseekable streams we want to avoid diff --git a/src/Tgstation.Server.Host/README.md b/src/Tgstation.Server.Host/README.md index ccb01971a64..1f8df0feee3 100644 --- a/src/Tgstation.Server.Host/README.md +++ b/src/Tgstation.Server.Host/README.md @@ -12,8 +12,8 @@ Server startup can be a bit complicated so here's a walkthrough 1. `CreateServer()` is called on the `IServerFactory` to get the `IServer` instance. - The factory pattern is used throughout TGS to construct implementations where the composition root is not sufficient. `ServerFactory` is somewhat of an exception to this because it exists outside of the dependency injection umbrella. 1. Inside `CreateServer()` we run the [setup code](./Setup) if need be. - - This is implemented as a separate [dotnet host](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-6.0) to the main server. -1. Still inside `CreateServer()` we configure the main [dotnet host (IHostBuilder)](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-6.0) using the application [Application](./Core/Application.cs) class as the [Startup class](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/startup?view=aspnetcore-6.0#the-startup-class). + - This is implemented as a separate [dotnet host](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-8.0) to the main server. +1. Still inside `CreateServer()` we configure the main [dotnet host (IHostBuilder)](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-8.0) using the application [Application](./Core/Application.cs) class as the [Startup class](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/startup?view=aspnetcore-8.0#the-startup-class). 1. The `IHostBuilder` is used to construct the return `Server` implementation. 1. `Run()` is called on the `IServer` instance. 1. The DI container is built using the [Application](./Core/Application.cs) class. diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index 0256395b7d6..4ef38513a42 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -89,7 +89,7 @@ IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateD // CURSED // https://github.com/dotnet/runtime/blob/30dc7e7aedb7aab085c7d9702afeae5bc5a43133/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs#L246-L249 -#if !NET6_0 +#if !NET8_0 #error Validate this monstrosity works on current .NET #endif IConfigurationSource cmdLineConfig, baseYmlConfig, environmentYmlConfig; @@ -141,7 +141,7 @@ IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateD var serverPortProvider = kestrelOptions.ApplicationServices.GetRequiredService(); kestrelOptions.ListenAnyIP( serverPortProvider.HttpApiPort, - listenOptions => listenOptions.Protocols = HttpProtocols.Http1AndHttp2); + listenOptions => listenOptions.Protocols = HttpProtocols.Http1); // Can't use Http1And2 without TLS. Let the reverse proxy handle it // with 515 we lost the ability to test this effectively. Just bump it slightly above the default and let the existing limit hold us back kestrelOptions.Limits.MaxRequestLineSize = 8400; diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index dcf5490971a..d11a12e45dd 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -512,16 +512,16 @@ async Task ConfigureDatabase(CancellationToken cancellati } while (true); - bool useWinAuth; + var useWinAuth = false; + var encrypt = false; if (databaseConfiguration.DatabaseType == DatabaseType.SqlServer && platformIdentifier.IsWindows) { var defaultResponse = serverAddressEntry?.AddressList.Any(IPAddress.IsLoopback) ?? false ? (bool?)true : null; useWinAuth = await PromptYesNo("Use Windows Authentication?", defaultResponse, cancellationToken); + encrypt = await PromptYesNo("Use encrypted connection?", false, cancellationToken); } - else - useWinAuth = false; await console.WriteAsync(null, true, cancellationToken); @@ -567,6 +567,7 @@ void CreateTestConnection(string connectionString) => { ApplicationName = assemblyInformationProvider.VersionPrefix, DataSource = serverAddress ?? "(local)", + Encrypt = encrypt, }; if (useWinAuth) diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index 8c9f98bd65e..a4418d7a5f5 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -202,16 +202,13 @@ async Task ConsumeReaders(global::System.Diagnostics.Process handle, Tas bool outputOpen = true, errorOpen = true; async Task GetNextLine() { -#if NET7_0_OR_GREATER -#error ReadLineAsync supports cancellation now -#endif if (outputOpen && outputReadTask == null) - outputReadTask = stdOutHandle.ReadLineAsync(); + outputReadTask = stdOutHandle.ReadLineAsync(disposeToken).AsTask(); if (errorOpen && errorReadTask == null) - errorReadTask = stdErrHandle.ReadLineAsync(); + errorReadTask = stdErrHandle.ReadLineAsync(disposeToken).AsTask(); - var completedTask = await Task.WhenAny(outputReadTask ?? errorReadTask, errorReadTask ?? outputReadTask).WaitAsync(disposeToken); + var completedTask = await Task.WhenAny(outputReadTask ?? errorReadTask, errorReadTask ?? outputReadTask); var line = await completedTask; if (completedTask == outputReadTask) { @@ -243,8 +240,8 @@ async Task GetNextLine() { if (fileStream != null) { - await writer.WriteLineAsync(text); - await writer.FlushAsync(); + await writer.WriteLineAsync(text.AsMemory(), disposeToken); + await writer.FlushAsync(disposeToken); } else stringBuilder.AppendLine(text); @@ -267,7 +264,7 @@ async Task GetNextLine() /// /// The to create a from. /// The based on . - IProcess CreateFromExistingHandle(global::System.Diagnostics.Process handle) + Process CreateFromExistingHandle(global::System.Diagnostics.Process handle) { try { diff --git a/src/Tgstation.Server.Host/System/SystemDManager.cs b/src/Tgstation.Server.Host/System/SystemDManager.cs index aa4efd944e7..90ffe101deb 100644 --- a/src/Tgstation.Server.Host/System/SystemDManager.cs +++ b/src/Tgstation.Server.Host/System/SystemDManager.cs @@ -53,7 +53,7 @@ sealed class SystemDManager : BackgroundService, IRestartHandler, IDisposable /// /// A representing the clock time in nanoseconds. /// See https://linux.die.net/man/3/clock_gettime. - static long GetMonotonicUsec() => global::System.Diagnostics.Stopwatch.GetTimestamp(); // HACK: https://github.com/dotnet/runtime/blob/v6.0.19/src/libraries/Native/Unix/System.Native/pal_time.c#L51 clock_gettime_nsec_np is an OSX only thing apparently... + static long GetMonotonicUsec() => global::System.Diagnostics.Stopwatch.GetTimestamp(); // HACK: https://github.com/dotnet/runtime/blob/v8.0.0-preview.6.23329.7/src/native/libs/System.Native/pal_time.c#L84 clock_gettime_nsec_np is an OSX only thing apparently... /// /// Initializes a new instance of the class. diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 559566784dd..e413cc6fe88 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -71,25 +71,25 @@ - + - + - + - + runtime; build; native; contentfiles; analyzers; buildtransitive - + - + - + @@ -113,13 +113,13 @@ - + - + - + diff --git a/src/Tgstation.Server.Host/Utils/README.md b/src/Tgstation.Server.Host/Utils/README.md index bad6a54616e..0eb93a26189 100644 --- a/src/Tgstation.Server.Host/Utils/README.md +++ b/src/Tgstation.Server.Host/Utils/README.md @@ -5,5 +5,5 @@ This is a bag of classes used throughout TGS that don't quite belong anywhere el - [IAsyncDelayer](./IAsyncDelayer.cs) and [implementation](./AsyncDelayer.cs) is a class used to sleep code. It's generally a no-op in test scenarios. - [IGitHubClientFactory](./IGitHubClientFactory.cs) and [implementation](./GitHubClientFactory.cs) is a class used to create GitHub API clients using [ocktokit.net](https://github.com/octokit/octokit.net). - [OpenApiEnumVarNamesExtension](./OpenApiEnumVarNamesExtension) implements the [x-var-names OpenAPI 3.0 extension](https://github.com/OpenAPITools/openapi-generator/blob/master/docs/templating.md#enum) in our generated API json. -- [SemaphoreSlimContext](./SemaphoreSlimContext.cs) is a helper class for working with [.NET asynchronous sempahores](https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=netcore-6.0). +- [SemaphoreSlimContext](./SemaphoreSlimContext.cs) is a helper class for working with [.NET asynchronous sempahores](https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=netcore-8.0). - [SwaggerConfiguration](./SwaggerConfiguration.cs) configures [Swashbuckle](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) to generate our OpenAPI specification. diff --git a/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs b/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs index 7ad15d9ad03..c60d7308c2a 100644 --- a/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs +++ b/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs @@ -181,6 +181,8 @@ public async Task TestWithUserStupidity() "no", //test winauth "yes", + // encrypt + "YES", //sql server will always fail so reconfigure with maria nameof(DatabaseType.MariaDB), "127.0.0.1", diff --git a/tests/Tgstation.Server.Host.Tests/Utils/TestAsyncDelayer.cs b/tests/Tgstation.Server.Host.Tests/Utils/TestAsyncDelayer.cs index 2760e9a4fe6..fcad8785c5c 100644 --- a/tests/Tgstation.Server.Host.Tests/Utils/TestAsyncDelayer.cs +++ b/tests/Tgstation.Server.Host.Tests/Utils/TestAsyncDelayer.cs @@ -13,8 +13,8 @@ public sealed class TestAsyncDelayer public async Task TestDelay() { var delayer = new AsyncDelayer(); - var startDelay = delayer.Delay(TimeSpan.FromSeconds(1), default); - var checkDelay = Task.Delay(TimeSpan.FromSeconds(1) - TimeSpan.FromMilliseconds(100), default); + var startDelay = delayer.Delay(TimeSpan.FromSeconds(1), CancellationToken.None); + var checkDelay = Task.Delay(TimeSpan.FromSeconds(1) - TimeSpan.FromMilliseconds(100), CancellationToken.None); await startDelay; Assert.IsTrue(checkDelay.IsCompleted); } diff --git a/tools/Tgstation.Server.Migrator/Program.cs b/tools/Tgstation.Server.Migrator/Program.cs index 83afbe25008..69783b68f3c 100644 --- a/tools/Tgstation.Server.Migrator/Program.cs +++ b/tools/Tgstation.Server.Migrator/Program.cs @@ -24,9 +24,9 @@ using Tgstation.Server.Common; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Common.Http; -using Tgstation.Server.Host.Common; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Setup; +using Tgstation.Server.Migrator.Properties; using FileMode = System.IO.FileMode; @@ -226,7 +226,7 @@ static ServiceController GetTgs3Service(bool checkNewOneIsntInstalled) Console.WriteLine("Attempting to create TGS install directory..."); Directory.CreateDirectory(tgsInstallPath); - // ASP.NET 6.0 RUNTIME CHECK + // 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."); @@ -253,14 +253,14 @@ static ServiceController GetTgs3Service(bool checkNewOneIsntInstalled) if (runtimeInstalled) { var versions = await dotnetRuntimeCheck.StandardOutput.ReadToEndAsync(); - var regex = new Regex("Microsoft\\.AspNetCore\\.App 6\\.0\\.[0-9]+"); + var regex = new Regex("Microsoft\\.AspNetCore\\.App 8\\.0\\.[0-9]+"); if (!regex.IsMatch(versions)) runtimeInstalled = false; } } - // ASP.NET 6.0 RUNTIME SETUP + // ASP.NET 8.0 RUNTIME SETUP var assemblyName = currentAssembly.GetName(); var productInfoHeaderValue = new ProductInfoHeaderValue( @@ -276,9 +276,9 @@ static ServiceController GetTgs3Service(bool checkNewOneIsntInstalled) var xSubstitution = x64 ? "64" : "86"; Console.WriteLine($"Running on an x{xSubstitution} system."); - var downloadUri = new Uri("https://download.visualstudio.microsoft.com/download/pr/eaa3eab9-cc21-44b5-a4e4-af31ee73b9fa/d8ad75d525dec0a30b52adc990796b11/dotnet-hosting-6.0.9-win.exe"); + var downloadUri = RuntimeDistributableAttribute.Instance.RuntimeDistributableUrl; - var dotnetDownloadFilePath = $"dotnet-hosting-6.0.9-win.exe"; + var dotnetDownloadFilePath = $"dotnet-hosting-bundle-installer.exe"; Console.WriteLine($"Downloading {downloadUri} to {Path.GetFullPath(dotnetDownloadFilePath)}..."); @@ -327,7 +327,7 @@ static ServiceController GetTgs3Service(bool checkNewOneIsntInstalled) if (!PromptYesOrNo("Was the installation successful?")) { - Console.WriteLine("Cannot continue without ASP.NET 6.0 runtime installed."); + Console.WriteLine("Cannot continue without ASP.NET 8.0 runtime installed."); ExitPause(2); } } diff --git a/tools/Tgstation.Server.Migrator/Properties/RuntimeDistributableAttribute.cs b/tools/Tgstation.Server.Migrator/Properties/RuntimeDistributableAttribute.cs new file mode 100644 index 00000000000..d4434c61bb6 --- /dev/null +++ b/tools/Tgstation.Server.Migrator/Properties/RuntimeDistributableAttribute.cs @@ -0,0 +1,34 @@ +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 index a74f718d7c1..2214e420928 100644 --- a/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj +++ b/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj @@ -1,9 +1,9 @@ - + Exe - $(TgsFrameworkVersion) + $(TgsFrameworkVersion) win-x86 $(TgsMigratorVersion) enable @@ -15,6 +15,19 @@ + + + + <_Parameter1>$(TgsDotnetRedistUrl) + + + + + + + + + From 67c4df356365aa00d5b3f1638dbcb38bf1b715ef Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 00:38:52 -0400 Subject: [PATCH 002/717] Workaround for https://github.com/dotnet/runtime/issues/89547 --- .../Configuration/SecurityConfiguration.cs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Configuration/SecurityConfiguration.cs b/src/Tgstation.Server.Host/Configuration/SecurityConfiguration.cs index b78cf55b9ab..a6073538cd9 100644 --- a/src/Tgstation.Server.Host/Configuration/SecurityConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/SecurityConfiguration.cs @@ -1,4 +1,7 @@ using System.Collections.Generic; +using System.Linq; + +using Swashbuckle.AspNetCore.SwaggerGen; using Tgstation.Server.Api.Models; @@ -62,6 +65,27 @@ public sealed class SecurityConfiguration /// /// OAuth provider settings. /// - public IDictionary OAuth { get; set; } + public IDictionary OAuth + { + get => oAuth; + set + { + // Workaround for https://github.com/dotnet/runtime/issues/89547 + var publicProperties = typeof(OAuthConfiguration) + .GetProperties() + .Where(property => property.CanWrite && property.SetMethod.IsPublic) + .ToList(); + oAuth = value + .Where( + kvp => !publicProperties.All( + prop => prop.GetValue(kvp.Value) == prop.PropertyType.GetDefaultValue())) + .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + } + } + + /// + /// Backing field for . + /// + IDictionary oAuth; } } From 58eb65373220423f0593e1672b4fc4d1a100c8d0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 00:47:22 -0400 Subject: [PATCH 003/717] Add missing `SelfContained` property to migrator --- tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj b/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj index 2214e420928..48ca05263dd 100644 --- a/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj +++ b/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj @@ -5,6 +5,7 @@ Exe $(TgsFrameworkVersion) win-x86 + true $(TgsMigratorVersion) enable CA1416 From 13d0489ed2259d9d5647b150237d7dfcf3ccfa3e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 00:48:52 -0400 Subject: [PATCH 004/717] Fix migrator references to V5 and update version --- build/Version.props | 2 +- .../Program.cs | 20 ++++---- tools/Tgstation.Server.Migrator/Program.cs | 46 +++++++++---------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/build/Version.props b/build/Version.props index d1fc8f38c31..44127192af6 100644 --- a/build/Version.props +++ b/build/Version.props @@ -13,7 +13,7 @@ 5.6.1 1.4.0 1.2.1 - 1.0.2 + 2.0.0 netstandard2.0 8 diff --git a/tools/Tgstation.Server.Migrator.Comms/Program.cs b/tools/Tgstation.Server.Migrator.Comms/Program.cs index 2e069acb460..e83f874734d 100644 --- a/tools/Tgstation.Server.Migrator.Comms/Program.cs +++ b/tools/Tgstation.Server.Migrator.Comms/Program.cs @@ -64,7 +64,7 @@ static async Task Migrate(IClient tgs3Client, ushort apiPort) Console.WriteLine("Connected!"); - Console.WriteLine("Connecting to TGS5..."); + Console.WriteLine("Connecting to TGS6..."); var assemblyName = Assembly.GetExecutingAssembly().GetName(); var productInfoHeaderValue = new ProductInfoHeaderValue( @@ -73,7 +73,7 @@ static async Task Migrate(IClient tgs3Client, ushort apiPort) var serverUrl = new Uri($"http://localhost:{apiPort}"); var clientFactory = new ServerClientFactory(productInfoHeaderValue.Product); - var tgs5Client = await clientFactory.CreateFromLogin( + var TGS6Client = await clientFactory.CreateFromLogin( serverUrl, DefaultCredentials.AdminUserName, DefaultCredentials.DefaultAdminUserPassword); @@ -217,7 +217,7 @@ static async Task Migrate(IClient tgs3Client, ushort apiPort) Console.WriteLine("Detaching TGS3 instance..."); tgs3Client.Server.InstanceManager.DetachInstance(instanceName); - Console.WriteLine("Creating TGS5 attach file..."); + Console.WriteLine("Creating TGS6 attach file..."); File.WriteAllText(Path.Combine(instancePath, "TGS4_ALLOW_INSTANCE_ATTACH"), String.Empty); Console.WriteLine("Checking BYOND install..."); @@ -309,22 +309,22 @@ static async Task Migrate(IClient tgs3Client, ushort apiPort) Console.WriteLine("Deleting TGDreamDaemonBridge.dll..."); File.Delete(Path.Combine(instancePath, "TGDreamDaemonBridge.dll")); - Console.WriteLine("Attaching TGS5 instance..."); - var tgs5Instance = await tgs5Client.Instances.CreateOrAttach(new InstanceCreateRequest + Console.WriteLine("Attaching TGS6 instance..."); + var TGS6Instance = await TGS6Client.Instances.CreateOrAttach(new InstanceCreateRequest { ConfigurationType = ConfigurationType.Disallowed, Name = instanceName, Path = instancePath, }, default); - Console.WriteLine($"Onlining TGS5 instance ID {tgs5Instance.Id}..."); - tgs5Instance = await tgs5Client.Instances.Update(new InstanceUpdateRequest + Console.WriteLine($"Onlining TGS6 instance ID {TGS6Instance.Id}..."); + TGS6Instance = await TGS6Client.Instances.Update(new InstanceUpdateRequest { Online = true, - Id = tgs5Instance.Id + Id = TGS6Instance.Id }, default); - var v5InstanceClient = tgs5Client.Instances.CreateClient(tgs5Instance); + var v5InstanceClient = TGS6Client.Instances.CreateClient(TGS6Instance); if (byondVersionRequest != null) { @@ -350,7 +350,7 @@ static async Task Migrate(IClient tgs3Client, ushort apiPort) await v5InstanceClient.ChatBots.Create(chatBotCreateRequest, default); } - Console.WriteLine($"Instance {instanceName} (TGS5 ID: {tgs5Instance.Id}) successfully migrated!"); + Console.WriteLine($"Instance {instanceName} (TGS6 ID: {TGS6Instance.Id}) successfully migrated!"); } Console.WriteLine("All enabled V3 instances migrated into V5 and detached from V3!"); diff --git a/tools/Tgstation.Server.Migrator/Program.cs b/tools/Tgstation.Server.Migrator/Program.cs index 69783b68f3c..651c5e18522 100644 --- a/tools/Tgstation.Server.Migrator/Program.cs +++ b/tools/Tgstation.Server.Migrator/Program.cs @@ -44,7 +44,7 @@ static void ExitPause(int exitCode) 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 TGS5 install"); + 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) { @@ -194,7 +194,7 @@ static ServiceController GetTgs3Service(bool checkNewOneIsntInstalled) 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 TGS5 setup wizard step by copying your premade appsettings.Production.yml file next to this .exe NOW."); + 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."); @@ -338,7 +338,7 @@ static ServiceController GetTgs3Service(bool checkNewOneIsntInstalled) } - // TGS5 ONLINE LOCATING + // 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)"); @@ -376,14 +376,14 @@ static ServiceController GetTgs3Service(bool checkNewOneIsntInstalled) ExitPause(4); } - // TGS5 SETUP WIZARD + // 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 - // TGS5 DOWNLOAD AND UNZIP - Console.WriteLine("Downloading TGS5..."); + // TGS6 DOWNLOAD AND UNZIP + Console.WriteLine("Downloading TGS6..."); using (var loggerFactory = LoggerFactory.Create(builder => { })) { @@ -397,7 +397,7 @@ static ServiceController GetTgs3Service(bool checkNewOneIsntInstalled) await using (tgsFiveZipBuffer) { - Console.WriteLine("Unzipping TGS5..."); + Console.WriteLine("Unzipping TGS6..."); await serverFactory.IOManager.ZipToDirectory( tgsInstallPath, await tgsFiveZipBuffer.GetResult(default), @@ -405,7 +405,7 @@ await tgsFiveZipBuffer.GetResult(default), } } - // TGS5 CONFIG SETUP + // TGS6 CONFIG SETUP const string ConfigurationFileName = "appsettings.Production.yml"; Console.WriteLine("Extracting API port from configuration..."); ushort configuredApiPort; @@ -424,8 +424,8 @@ await tgsFiveZipBuffer.GetResult(default), Console.WriteLine("Moving configuration file from setup wizard to installation folder..."); File.Copy(ConfigurationFileName, Path.Combine(tgsInstallPath, ConfigurationFileName)); - // TGS5 SERVICE SETUP - Console.WriteLine("Installing TGS5 service..."); + // TGS6 SERVICE SETUP + Console.WriteLine("Installing TGS6 service..."); using (var processInstaller = new ServiceProcessInstaller()) using (var installer = new ServiceInstaller()) { @@ -448,42 +448,42 @@ await tgsFiveZipBuffer.GetResult(default), installer.Install(state); } - Console.WriteLine("Starting TGS5 service..."); + Console.WriteLine("Starting TGS6 service..."); var allServices = ServiceController.GetServices(); - using (var tgs5Service = allServices.FirstOrDefault(service => service.ServiceName == NewServiceName)) + using (var TGS6Service = allServices.FirstOrDefault(service => service.ServiceName == NewServiceName)) { - if (tgs5Service == null) + if (TGS6Service == null) { - Console.WriteLine("Unable to locate newly installed TGS5 service!"); + Console.WriteLine("Unable to locate newly installed TGS6 service!"); ExitPause(11); } foreach (var service in allServices) { - if (service == tgs5Service) + if (service == TGS6Service) continue; service.Dispose(); } - tgs5Service.Start(); - tgs5Service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromMinutes(2)); + TGS6Service.Start(); + TGS6Service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromMinutes(2)); } - // TGS5 CLIENT CONNECTION + // TGS6 CLIENT CONNECTION const int MaxWaitMinutes = 5; - Console.WriteLine($"Connecting to TGS5 (Max {MaxWaitMinutes} minute wait)..."); + 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 ServerClientFactory(productInfoHeaderValue.Product); - IServerClient tgs5Client; + IServerClient TGS6Client; for (var I = 1; ; ++I) { try { Console.WriteLine($"Attempt {I}..."); - tgs5Client = await clientFactory.CreateFromLogin( + TGS6Client = await clientFactory.CreateFromLogin( serverUrl, DefaultCredentials.AdminUserName, DefaultCredentials.DefaultAdminUserPassword); @@ -505,7 +505,7 @@ await tgsFiveZipBuffer.GetResult(default), } } - Console.WriteLine("Successfully connected to TGS5!"); + Console.WriteLine("Successfully connected to TGS6!"); // COMMS MIGRATION Console.WriteLine("Deferring to Comms binary to migrate instances..."); @@ -533,7 +533,7 @@ await tgsFiveZipBuffer.GetResult(default), 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 TGS5 using an interactive client to build and start your server."); + Console.WriteLine("Then configure TGS6 using an interactive client to build and start your server."); ExitPause(0); } catch (Exception ex) From dc0ab131f24fabaf8ddae76248cc12abac8e3bfb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 01:03:01 -0400 Subject: [PATCH 005/717] Fix Dockerfile FROM statements --- build/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index 7985eb8c9ac..ed2e2ed0d87 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0-preview-bookworm-slim AS build # install node and npm # replace shell with bash so we can source files @@ -63,7 +63,7 @@ RUN dotnet publish -c Release -o /app WORKDIR /repo/src/Tgstation.Server.Host RUN dotnet publish -c Release -o /app/lib/Default && mv /app/lib/Default/appsettings* /app -FROM mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim +FROM mcr.microsoft.com/dotnet/aspnet:8.0-preview-bookworm-slim #needed for byond RUN apt-get update \ From c3bfff39b86d24e5f4dcb9fb02fb1d641a7021fd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 01:04:04 -0400 Subject: [PATCH 006/717] setup-dotnet in `Code Scanning` workflow --- .github/workflows/code-scanning.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml index 36afb0999f6..4ee97c4771d 100644 --- a/.github/workflows/code-scanning.yml +++ b/.github/workflows/code-scanning.yml @@ -14,6 +14,9 @@ on: - master - V6 +env: + TGS_DOTNET_VERSION: 8.0.x + concurrency: group: "code-scanning-${{ github.head_ref || github.run_id }}-${{ github.event_name }}" cancel-in-progress: true @@ -28,6 +31,11 @@ jobs: security-events: write if: ${{ vars.TGS_ENABLE_CODE_QL }} == 'true' steps: + - name: Setup dotnet + uses: actions/setup-dotnet@v2 + with: + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + - name: Checkout uses: actions/checkout@v3 From c5bcb02836f2994f36dbc44d7fa87485e16f1303 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 01:06:15 -0400 Subject: [PATCH 007/717] Fix `setup-dotnet` calls --- .github/workflows/ci-pipeline.yml | 50 +++++++++++++++-------------- .github/workflows/code-scanning.yml | 8 +++-- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 4428c8d513b..99dfab1bd8c 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -38,7 +38,8 @@ on: - V6 env: - TGS_DOTNET_VERSION: 8.0.x + TGS_DOTNET_VERSION: 8 + TGS_DOTNET_QUALITY: preview TGS_TEST_GITHUB_TOKEN: ${{ secrets.LIVE_TESTS_TOKEN }} TGS_RELEASE_NOTES_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} WINGET_PUSH_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} @@ -244,9 +245,9 @@ jobs: sudo apt-get install -y -o APT::Immediate-Configure=0 libc6-i386 libstdc++6:i386 libgcc-s1:i386 - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' - name: Checkout (Branch) uses: actions/checkout@v3 @@ -287,9 +288,9 @@ jobs: runs-on: windows-latest steps: - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' - name: Checkout (Branch) uses: actions/checkout@v3 @@ -336,9 +337,9 @@ jobs: sqlcmd -l 600 -S "(localdb)\MSSQLLocalDB" -Q "SELECT @@VERSION;" - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' - name: Set TGS_TEST_DUMP_API_SPEC if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'System' && matrix.database-type == 'SqlServer' }} @@ -532,9 +533,9 @@ jobs: sudo apt-get install -y -o APT::Immediate-Configure=0 libc6-i386 libstdc++6:i386 gdb libgcc-s1:i386 - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' - name: Set Sqlite Connection Info if: ${{ matrix.database-type == 'Sqlite' }} @@ -936,12 +937,13 @@ jobs: - name: Install dotnet-sdk system package run: | sudo apt-get update - sudo apt-get install -y dotnet-sdk-${{ env.TGS_DOTNET_VERSION }} + sudo apt-get install -y dotnet-sdk-${{ env.TGS_DOTNET_VERSION }}.0 - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Override /usr/bin/dotnet run: | @@ -1025,9 +1027,9 @@ jobs: GITHUB_TOKEN: ${{ env.WINGET_PUSH_TOKEN }} - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' - name: Checkout (Branch) uses: actions/checkout@v3 @@ -1150,9 +1152,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' - name: Retrieve Latest winget-pkgs PULL_REQUEST_TEMPLATE commit SHA from GitHub API id: get-sha @@ -1289,9 +1291,9 @@ jobs: if: "!(cancelled() || failure()) && needs.upload-code-coverage.result == 'success' && needs.validate-openapi-spec.result == 'success' && github.event_name == 'push' && contains(github.event.head_commit.message, '[NugetDeploy]')" steps: - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' - name: Checkout uses: actions/checkout@v3 @@ -1327,9 +1329,9 @@ jobs: if: "!(cancelled() || failure()) && (needs.deploy-dm.result == 'success' || needs.deploy-http.result == 'success') && !contains(github.event.head_commit.message, '[TGSDeploy]')" steps: - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' - name: Checkout uses: actions/checkout@v3 @@ -1350,9 +1352,9 @@ jobs: if: "!(cancelled() || failure()) && needs.deployment-gate.result == 'success' && github.event.ref == 'refs/heads/master' && contains(github.event.head_commit.message, '[TGSDeploy]')" steps: - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' - name: Checkout uses: actions/checkout@v3 @@ -1588,9 +1590,9 @@ jobs: runs-on: windows-latest steps: - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' - name: Install winget uses: Cyberboss/install-winget@v1 diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml index 4ee97c4771d..0b9db119bfc 100644 --- a/.github/workflows/code-scanning.yml +++ b/.github/workflows/code-scanning.yml @@ -15,7 +15,8 @@ on: - V6 env: - TGS_DOTNET_VERSION: 8.0.x + TGS_DOTNET_VERSION: 8 + TGS_DOTNET_QUALITY: preview concurrency: group: "code-scanning-${{ github.head_ref || github.run_id }}-${{ github.event_name }}" @@ -32,9 +33,10 @@ jobs: if: ${{ vars.TGS_ENABLE_CODE_QL }} == 'true' steps: - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.x' + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout uses: actions/checkout@v3 From 57c8eebda9fd4b89e2a1a8dc115113e2f84ee5dc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 01:14:33 -0400 Subject: [PATCH 008/717] Allow .deb to build while in .NET preview --- .github/workflows/ci-pipeline.yml | 1 + build/package/deb/build_package.sh | 11 ++++++++++- build/package/deb/debian/control | 4 ++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 99dfab1bd8c..266a81f8694 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -935,6 +935,7 @@ jobs: rm private.pgp - name: Install dotnet-sdk system package + if: "!contains(env.TGS_DOTNET_QUALITY, 'preview')" run: | sudo apt-get update sudo apt-get install -y dotnet-sdk-${{ env.TGS_DOTNET_VERSION }}.0 diff --git a/build/package/deb/build_package.sh b/build/package/deb/build_package.sh index 2f81abb1e01..91524707e97 100755 --- a/build/package/deb/build_package.sh +++ b/build/package/deb/build_package.sh @@ -8,7 +8,16 @@ set -x dpkg --add-architecture i386 apt-get update -apt-get install -y npm dotnet-sdk-8.0 build-essential binutils lintian debhelper dh-make devscripts xmlstarlet # needs cleanup probably, SO copypasta +# This package set needs cleanup probably, StackOverflow copypasta +apt-get install -y npm \ + build-essential \ + binutils \ + lintian \ + debhelper \ + dh-make \ + devscripts \ + xmlstarlet +# dotnet-sdk-8.0 # Disabled while in preview CURRENT_COMMIT=$(git rev-parse HEAD) diff --git a/build/package/deb/debian/control b/build/package/deb/debian/control index ee30543ecf4..486be1bcf27 100644 --- a/build/package/deb/debian/control +++ b/build/package/deb/debian/control @@ -5,8 +5,8 @@ Maintainer: Jordan Dominion Rules-Requires-Root: no Build-Depends: debhelper-compat (= 13), - dotnet-sdk-8.0, npm, +#dotnet-sdk-8.0, Disabled while in preview Standards-Version: 4.6.2 Homepage: https://tgstation.github.io/tgstation-server Vcs-Browser: https://github.com/tgstation/tgstation-server @@ -16,7 +16,7 @@ Package: tgstation-server Architecture: any Depends: ${misc:Depends}, - aspnetcore-runtime-8.0, +#aspnetcore-runtime-8.0, Disabled while in preview libc6-i386, libstdc++6:i386 [amd64], libstdc++6 [i386], From 1eee2ce9d8fcc9c68a54cea3847422d30a9d6ca4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 01:40:42 -0400 Subject: [PATCH 009/717] Fix release build issues --- build/Version.props | 2 +- src/Tgstation.Server.Client/Components/ConfigurationClient.cs | 2 +- src/Tgstation.Server.Client/ServerClientFactory.cs | 2 +- src/Tgstation.Server.Host/Components/Byond/ByondManager.cs | 2 +- src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs | 2 +- src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs | 1 - src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 2 +- 7 files changed, 6 insertions(+), 7 deletions(-) diff --git a/build/Version.props b/build/Version.props index 44127192af6..a65853b9807 100644 --- a/build/Version.props +++ b/build/Version.props @@ -8,7 +8,7 @@ 9.11.0 6.0.0 11.0.0 - 12.0.0 + 13.0.0 6.5.2 5.6.1 1.4.0 diff --git a/src/Tgstation.Server.Client/Components/ConfigurationClient.cs b/src/Tgstation.Server.Client/Components/ConfigurationClient.cs index 581c1ad791c..378811083d6 100644 --- a/src/Tgstation.Server.Client/Components/ConfigurationClient.cs +++ b/src/Tgstation.Server.Client/Components/ConfigurationClient.cs @@ -53,7 +53,7 @@ public async Task> Read(IConfigurationF if (file == null) throw new ArgumentNullException(nameof(file)); var configFile = await ApiClient.Read( - Routes.ConfigurationFile + Routes.SanitizeGetPath(file.Path ?? throw new ArgumentException("file.Path should not be null!", nameof(file))), + Routes.ConfigurationFile + Routes.SanitizeGetPath(file.Path ?? throw new InvalidOperationException("file.Path should not be null!")), instance.Id!.Value, cancellationToken) .ConfigureAwait(false); diff --git a/src/Tgstation.Server.Client/ServerClientFactory.cs b/src/Tgstation.Server.Client/ServerClientFactory.cs index b27e4dd9c51..b611bd36da6 100644 --- a/src/Tgstation.Server.Client/ServerClientFactory.cs +++ b/src/Tgstation.Server.Client/ServerClientFactory.cs @@ -100,7 +100,7 @@ public IServerClient CreateFromToken(Uri host, TokenResponse token) if (token == null) throw new ArgumentNullException(nameof(token)); if (token.Bearer == null) - throw new ArgumentException("token.Bearer should not be null!", nameof(token)); + throw new InvalidOperationException("token.Bearer should not be null!"); return new ServerClient(ApiClientFactory.CreateApiClient(host, new ApiHeaders(productHeaderValue, token.Bearer), null, false), token); } diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs b/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs index 16fa34998d6..a10fdb84253 100644 --- a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs +++ b/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs @@ -107,7 +107,7 @@ static void CheckVersionParameter(Version version) ArgumentNullException.ThrowIfNull(version); if (version.Build == 0) - throw new ArgumentException("version.Build cannot be 0!", nameof(version)); + throw new InvalidOperationException("version.Build cannot be 0!"); } /// diff --git a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs index 22233ce36b8..aa34c3cc7bd 100644 --- a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs @@ -148,7 +148,7 @@ public void CheckCompatibility(ILogger logger) else if (ConfigVersion != CurrentConfigVersion) if (ConfigVersion.Major != CurrentConfigVersion.Major) logger.LogCritical( - "Your `ConfigVersion` is majorly out-of-date and may potentially cause issues running the server. Please follow migration instructions from the TGS release notes.", + "Your `ConfigVersion` is majorly out-of-date and may potentially cause issues running the server. Please follow migration instructions from the TGS release notes. The current version is \"{currentVersion}\"", CurrentConfigVersion); else logger.LogWarning("Your `ConfigVersion` is out-of-date. Please follow migration instructions from the TGS release notes."); diff --git a/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs b/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs index 4402b956b95..3997e0a46b3 100644 --- a/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs @@ -1,5 +1,4 @@ using System; -using System.Data.SqlClient; using Microsoft.EntityFrameworkCore; diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index e413cc6fe88..a2e5dc9368c 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -6,7 +6,7 @@ $(TgsCoreVersion) true false - API1000 + API1000;ASP0019 ClientApp/node_modules ClientApp/node_modules/.install-stamp Linux From efa3d6a47a231612562a90847c4b015689be5df2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 01:47:48 -0400 Subject: [PATCH 010/717] Remove explicit restore step from docker build --- build/Dockerfile | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index ed2e2ed0d87..fb9869909b1 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -40,22 +40,11 @@ RUN dotnet msbuild -target:NpmBuild WORKDIR /repo -# Restore nuget packages -COPY tgstation-server.sln ./ - -COPY src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj src/Tgstation.Server.Host.Console/ -COPY src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj src/Tgstation.Server.Host.Watchdog/ -COPY src/Tgstation.Server.Api/Tgstation.Server.Api.csproj src/Tgstation.Server.Api/ -COPY src/Tgstation.Server.Common/Tgstation.Server.Common.csproj src/Tgstation.Server.Common/ -COPY src/Tgstation.Server.Host.Common/Tgstation.Server.Host.Common.csproj src/Tgstation.Server.Host.Common/ - -RUN dotnet restore -nowarn:MSB3202,nu1503 -p:RestoreUseSkipNonexistentTargets=false - # Final copy for building COPY . . #run dos2unix on tgs.docker.sh so we can build without issue on windows -RUN dos2unix build/tgs.docker.sh +RUN dos2unix build/tgs.docker.sh && dotnet restore WORKDIR /repo/src/Tgstation.Server.Host.Console RUN dotnet publish -c Release -o /app From da5a9d80ae08918be08435c151612bd07fcb6bc1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 01:59:54 -0400 Subject: [PATCH 011/717] Do not .dockerignore any solution projects --- .dockerignore | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.dockerignore b/.dockerignore index 3d9e0e32dd5..4ce7bb37b3d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -12,7 +12,7 @@ appveyor.yml omnisharp.json README.md -build/package/** +build/package/deb build/ci.runsettings build/Dockerfile build/GenerateMigrations.sh @@ -26,9 +26,6 @@ src/Tgstation.Server.Host/appsettings.Development.json src/Tgstation.Server.Host/appsettings.Development.yml src/Tgstation.Server.Host/tgs.bat src/Tgstation.Server.Host/tgs.sh -src/Tgstation.Server.Client -src/Tgstation.Server.Host.Service -tests -tools +tests/DMAPI artifacts packaging From aeda043912f6ee57344c7369d512e535b51df564 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 02:11:57 -0400 Subject: [PATCH 012/717] Copy all .props in docker build at once --- build/Dockerfile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index fb9869909b1..3f66f560671 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -25,11 +25,7 @@ RUN npm install -g yarn # Build web control panel WORKDIR /repo/build -COPY build/Common.props Common.props -COPY build/NugetCommon.props NugetCommon.props -COPY build/Version.props Version.props -COPY build/ControlPanelVersion.props ControlPanelVersion.props -COPY build/SrcCommon.props SrcCommon.props +COPY build/*.props ./ WORKDIR /repo/src/Tgstation.Server.Host From 52c78d28dc6ee7ef365bc627392ce16bbe223fad Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 08:27:06 -0400 Subject: [PATCH 013/717] Downgrade EF for now as MySQL and PGSQL connecters don't yet support it --- .../Tgstation.Server.Host.csproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index a2e5dc9368c..157e581818e 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -75,21 +75,21 @@ - + - + runtime; build; native; contentfiles; analyzers; buildtransitive - + - + - + @@ -119,7 +119,7 @@ - + From 85591b8ec68a56c645c1f1a939b14b544e7ccedf Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 19:31:37 -0400 Subject: [PATCH 014/717] Add `Encrypt=false` to hardcoded MSSQL connection strings --- .github/workflows/ci-pipeline.yml | 2 +- .../Database/Design/SqlServerDesignTimeDbContextFactory.cs | 2 +- src/Tgstation.Server.Host/appsettings.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 266a81f8694..986dec0bbd0 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -393,7 +393,7 @@ jobs: if: ${{ matrix.database-type == 'SqlServer' }} shell: bash run: | - TGS_CONNSTRING_VALUE="Server=(localdb)\MSSQLLocalDB;Integrated Security=true;Initial Catalog=TGS_${{ matrix.watchdog-type }}_${{ matrix.configuration }};Application Name=tgstation-server" + TGS_CONNSTRING_VALUE="Server=(localdb)\MSSQLLocalDB;Encrypt=false;Integrated Security=true;Initial Catalog=TGS_${{ matrix.watchdog-type }}_${{ matrix.configuration }};Application Name=tgstation-server" echo "TGS_TEST_CONNECTION_STRING=$(echo $TGS_CONNSTRING_VALUE)" >> $GITHUB_ENV echo "TGS_TEST_DATABASE_TYPE=SqlServer" >> $GITHUB_ENV diff --git a/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs index bf137fcf4bc..9b5623725e1 100644 --- a/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs @@ -14,6 +14,6 @@ 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")); + "Data Source=fake;Initial Catalog=TGS_Design;Integrated Security=True;Encrypt=false;Application Name=tgstation-server")); } } diff --git a/src/Tgstation.Server.Host/appsettings.yml b/src/Tgstation.Server.Host/appsettings.yml index 7b0f60e8a3a..bebeb79c043 100644 --- a/src/Tgstation.Server.Host/appsettings.yml +++ b/src/Tgstation.Server.Host/appsettings.yml @@ -46,7 +46,7 @@ Updates: Database: DatabaseType: SqlServer # The database type TGS connects to ServerVersion: # The version of the database being connected to, generally not required to be specified - ConnectionString: Data Source=(local);Initial Catalog=TGS;Integrated Security=True # The connection string used to establish the database connection. Format varies for each DatabaseType + ConnectionString: Data Source=(local);Initial Catalog=TGS;Integrated Security=True;Encrypt=false # The connection string used to establish the database connection. Format varies for each DatabaseType DropDatabase: false # DANGEROUS! Causes TGS to recreate its database on startup. Must be unset manually ResetAdminPassword: false # DANGEROUS! Causes TGS to reset the `Admin` user password back to its default value on startup. Must be unset manually. Security: From 077ab16b2507cca62ce4aae985f160af48812459 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 27 Jul 2023 23:41:48 -0400 Subject: [PATCH 015/717] Add required reference to System.Security.Permissions for EFCore version bridging --- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 157e581818e..1d5d79f37de 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -118,6 +118,8 @@ + + From fc007543dbfa888cd274e5a54a512e830641fd1b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 28 Jul 2023 15:31:41 -0400 Subject: [PATCH 016/717] Switch to portable PDBs This is needed to fix a .pdb lockup issue with GHA logger + coverlet. See repro in 7aba43488d064b6bc67ef80116bc1198e98557ac --- build/Common.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/Common.props b/build/Common.props index c081f2e0d77..40e797c1695 100644 --- a/build/Common.props +++ b/build/Common.props @@ -4,6 +4,7 @@ net$(TgsNetMajorVersion).0 latest - Full + + From aaf7f1639e2051255de3bd6e2e7783caf511043b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 29 Jul 2023 13:13:10 -0400 Subject: [PATCH 017/717] Workaround for https://github.com/coverlet-coverage/coverlet/issues/1507 --- .../Configuration/FileLoggingConfiguration.cs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs b/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs index 48b08b5b485..3685be3ec84 100644 --- a/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs @@ -19,16 +19,6 @@ public sealed class FileLoggingConfiguration /// public const string Section = "FileLogging"; - /// - /// Default value for . - /// - const LogLevel DefaultLogLevel = LogLevel.Debug; - - /// - /// Default value for . - /// - const LogLevel DefaultMicrosoftLogLevel = LogLevel.Warning; - /// /// Where log files are stored. /// @@ -43,13 +33,13 @@ public sealed class FileLoggingConfiguration /// The minimum to display in logs. /// [JsonConverter(typeof(StringEnumConverter))] - public LogLevel LogLevel { get; set; } = DefaultLogLevel; + public LogLevel LogLevel { get; set; } = LogLevel.Debug; // Not a `const` b/c of https://github.com/coverlet-coverage/coverlet/issues/1507 /// /// The minimum to display in logs for Microsoft library sources. /// [JsonConverter(typeof(StringEnumConverter))] - public LogLevel MicrosoftLogLevel { get; set; } = DefaultMicrosoftLogLevel; + public LogLevel MicrosoftLogLevel { get; set; } = LogLevel.Warning; // Not a `const` b/c of https://github.com/coverlet-coverage/coverlet/issues/1507 /// /// Gets the evaluated log . From c1c09c5b51db9a3fb032b22e38cc500ac162cfcb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 13 Aug 2023 14:08:13 -0400 Subject: [PATCH 018/717] Update to .NET 8 preview 7 --- build/Version.props | 2 +- .../Tgstation.Server.Host.Console.csproj | 2 +- .../Tgstation.Server.Host.Service.csproj | 8 ++++---- .../Tgstation.Server.Host.Watchdog.csproj | 2 +- .../Tgstation.Server.Host.csproj | 12 +++++------- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/build/Version.props b/build/Version.props index fef8a1b33a0..678573c06c6 100644 --- a/build/Version.props +++ b/build/Version.props @@ -17,7 +17,7 @@ netstandard2.0 8 - https://download.visualstudio.microsoft.com/download/pr/e5db48f5-99c6-42ca-804a-85b89ae09671/b5594181b347a9a77246e3645916bd0e/dotnet-hosting-8.0.0-preview.6.23329.11-win.exe + https://download.visualstudio.microsoft.com/download/pr/e465df26-2f50-432f-a588-51c7682fd9b1/9efca17f575afd387aa9b02fb3dfb7e1/dotnet-hosting-8.0.0-preview.7.23375.9-win.exe 11.0.2 https://ftp.osuosl.org/pub/mariadb/mariadb-11.0.2/winx64-packages/mariadb-11.0.2-winx64.msi 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 ebe2348e40d..791ab81994a 100644 --- a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj +++ b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj @@ -11,7 +11,7 @@ - + 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 1e102db9959..cecc5194797 100644 --- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj +++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj @@ -19,15 +19,15 @@ - + - + - + - + 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 bfd4955b3bb..df0f2e69999 100644 --- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj +++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 429d93d2792..fdac8b2b1c0 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -71,9 +71,9 @@ - + - + @@ -111,13 +111,11 @@ - - - + - + - + From 2fa35a403bb7c14740937b505b534c4f2e29c602 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 13 Aug 2023 14:09:36 -0400 Subject: [PATCH 019/717] Fix code scanning issue --- src/Tgstation.Server.Api/ApiHeaders.cs | 3 ++- src/Tgstation.Server.Host/Models/ChatChannel.cs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Api/ApiHeaders.cs b/src/Tgstation.Server.Api/ApiHeaders.cs index 7dc1d79e7e5..7ee712130a2 100644 --- a/src/Tgstation.Server.Api/ApiHeaders.cs +++ b/src/Tgstation.Server.Api/ApiHeaders.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Net.Http.Headers; using System.Net.Mime; @@ -331,7 +332,7 @@ public void SetRequestHeaders(HttpRequestHeaders headers, long? instanceId = nul instanceId ??= InstanceId; if (instanceId.HasValue) - headers.Add(InstanceIdHeader, instanceId.ToString()); + headers.Add(InstanceIdHeader, instanceId.Value.ToString(CultureInfo.InvariantCulture)); } } } diff --git a/src/Tgstation.Server.Host/Models/ChatChannel.cs b/src/Tgstation.Server.Host/Models/ChatChannel.cs index 902c80bdb93..8519ffffdbb 100644 --- a/src/Tgstation.Server.Host/Models/ChatChannel.cs +++ b/src/Tgstation.Server.Host/Models/ChatChannel.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Globalization; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; @@ -41,7 +42,7 @@ public sealed class ChatChannel : ChatChannelBase /// The converted . public Api.Models.ChatChannel ToApi(ChatProvider chatProvider) => new Api.Models.ChatChannel { - ChannelData = chatProvider == ChatProvider.Discord ? DiscordChannelId.ToString() : IrcChannel, + ChannelData = chatProvider == ChatProvider.Discord ? DiscordChannelId.Value.ToString(CultureInfo.InvariantCulture) : IrcChannel, #pragma warning disable CS0618 IrcChannel = IrcChannel, DiscordChannelId = DiscordChannelId, From 651c810496bf26f784f2fbcf48c9e0b7f9f8766d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 13 Aug 2023 20:58:44 -0400 Subject: [PATCH 020/717] Fix issue with token claim mapping --- src/Tgstation.Server.Host/Core/Application.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 591953c0d89..5718d2cd1dd 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IdentityModel.Tokens.Jwt; using System.Linq; using Cyberboss.AspNetCore.AsyncInitializer; @@ -224,6 +223,7 @@ public void ConfigureServices( // this line isn't actually run until the first request is made // at that point tokenFactory will be populated jwtBearerOptions.TokenValidationParameters = tokenFactory.ValidationParameters; + jwtBearerOptions.MapInboundClaims = false; jwtBearerOptions.Events = new JwtBearerEvents { // Application is our composition root so this monstrosity of a line is okay @@ -238,11 +238,6 @@ public void ConfigureServices( }; }); - // WARNING: STATIC CODE - // fucking prevents converting 'sub' to M$ bs - // can't be done in the above lambda, that's too late - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); - // add mvc, configure the json serializer settings services .AddMvc(options => From 261ac08985abfb77eae6bd3b33cdc27b1de40159 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 15 Aug 2023 18:23:59 -0400 Subject: [PATCH 021/717] Removes "Based on what?" meme Linus Tech Tips is cancelled --- build/Version.props | 4 ++-- .../Models/DiscordConnectionStringBuilder.cs | 18 +++++++-------- .../Chat/Providers/DiscordProvider.cs | 22 ------------------- .../Live/Instance/ChatTest.cs | 1 - .../Live/Instance/InstanceTest.cs | 1 - .../Program.cs | 1 - 6 files changed, 10 insertions(+), 37 deletions(-) diff --git a/build/Version.props b/build/Version.props index e301751a07f..c6b95d7f1a1 100644 --- a/build/Version.props +++ b/build/Version.props @@ -5,9 +5,9 @@ 6.0.0 5.0.0 - 9.11.1 + 10.0.0 6.0.0 - 11.0.1 + 12.0.0 13.0.0 6.5.2 5.6.1 diff --git a/src/Tgstation.Server.Api/Models/DiscordConnectionStringBuilder.cs b/src/Tgstation.Server.Api/Models/DiscordConnectionStringBuilder.cs index c51d74a49fc..7ab64442ce8 100644 --- a/src/Tgstation.Server.Api/Models/DiscordConnectionStringBuilder.cs +++ b/src/Tgstation.Server.Api/Models/DiscordConnectionStringBuilder.cs @@ -19,11 +19,6 @@ public sealed class DiscordConnectionStringBuilder : ChatConnectionStringBuilder /// See https://discordapp.com/developers/docs/topics/oauth2#bots public string? BotToken { get; set; } - /// - /// to enable based mode. Will auto reply with a youtube link to a video that says "based on the hardware that's installed in it" to anyone saying 'based on what?' case-insensitive. - /// - public bool BasedMeme { get; set; } - /// /// If the tgstation-server logo is shown in deployment embeds. /// @@ -34,12 +29,17 @@ public sealed class DiscordConnectionStringBuilder : ChatConnectionStringBuilder /// public DiscordDMOutputDisplayType DMOutputDisplay { get; set; } + /// + /// Currently unused. Note its origin in based meme before repurposing. + /// + readonly bool unusedFlag; + + /// /// Initializes a new instance of the class. /// public DiscordConnectionStringBuilder() { - BasedMeme = true; } /// @@ -60,9 +60,7 @@ public DiscordConnectionStringBuilder(string connectionString) DMOutputDisplay = dMOutputDisplayType; if (splits.Length > 2 && Int32.TryParse(splits[2], out Int32 basedMeme)) - BasedMeme = Convert.ToBoolean(basedMeme); - else - BasedMeme = true; // oranges said this needs to be true by default :pensive: + unusedFlag = Convert.ToBoolean(basedMeme); if (splits.Length > 3 && Int32.TryParse(splits[3], out Int32 branding)) DeploymentBranding = Convert.ToBoolean(branding); @@ -71,6 +69,6 @@ public DiscordConnectionStringBuilder(string connectionString) } /// - public override string ToString() => $"{BotToken};{(int)DMOutputDisplay};{Convert.ToInt32(BasedMeme)};{Convert.ToInt32(DeploymentBranding)}"; + public override string ToString() => $"{BotToken};{(int)DMOutputDisplay};{Convert.ToInt32(unusedFlag)};{Convert.ToInt32(DeploymentBranding)}"; } } diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 142513c2756..937105594d3 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -82,11 +82,6 @@ public override string BotMention /// readonly object connectDisconnectLock; - /// - /// to enable based mode. Will auto reply with a youtube link to a video that says "based on the hardware that's installed in it" to anyone saying 'based on what?' case-insensitive. - /// - readonly bool basedMeme; - /// /// If the tgstation-server logo is shown in deployment embeds. /// @@ -199,7 +194,6 @@ public DiscordProvider( var csb = new DiscordConnectionStringBuilder(chatBot.ConnectionString); var botToken = csb.BotToken; - basedMeme = csb.BasedMeme; outputDisplayType = csb.DMOutputDisplay; deploymentBranding = csb.DeploymentBranding; @@ -514,22 +508,6 @@ public async Task RespondAsync(IMessageCreate messageCreateEvent, Cancel FailIfNotExists = false, }; - if (basedMeme && messageCreateEvent.Content.Equals("Based on what?", StringComparison.OrdinalIgnoreCase)) - { - await SendMessage( - new DiscordMessage - { - MessageReference = messageReference, - }, - new MessageContent - { - Text = "https://youtu.be/LrNu-SuFF_o", - }, - messageCreateEvent.ChannelID.Value, - cancellationToken); - return Result.FromSuccess(); - } - var channelsClient = serviceProvider.GetRequiredService(); var channelResponse = await channelsClient.GetChannelAsync(messageCreateEvent.ChannelID, cancellationToken); if (!channelResponse.IsSuccess) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ChatTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ChatTest.cs index f90c1dc116e..02faa835ca4 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ChatTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ChatTest.cs @@ -149,7 +149,6 @@ async Task RunDiscord(CancellationToken cancellationToken) // needs to just be valid connectionString = new DiscordConnectionStringBuilder { - BasedMeme = true, BotToken = "some_token", DeploymentBranding = true, DMOutputDisplay = DiscordDMOutputDisplayType.Never, diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 3035e45de99..9265e0e7f6e 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -97,7 +97,6 @@ public async Task RunCompatTests( // needs to just be valid connectionString = new DiscordConnectionStringBuilder { - BasedMeme = true, BotToken = "some_token", DeploymentBranding = true, DMOutputDisplay = DiscordDMOutputDisplayType.Always, diff --git a/tools/Tgstation.Server.Migrator.Comms/Program.cs b/tools/Tgstation.Server.Migrator.Comms/Program.cs index e83f874734d..754d9e69d58 100644 --- a/tools/Tgstation.Server.Migrator.Comms/Program.cs +++ b/tools/Tgstation.Server.Migrator.Comms/Program.cs @@ -168,7 +168,6 @@ static async Task Migrate(IClient tgs3Client, ushort apiPort) var discordSetupInfo = new DiscordSetupInfo(providerInfo); csb = new DiscordConnectionStringBuilder { - BasedMeme = false, DMOutputDisplay = DiscordDMOutputDisplayType.Always, BotToken = discordSetupInfo.BotToken }; From a9086530e2d5fc6b1f4406a678700bc04b36e021 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 15 Aug 2023 23:26:49 -0400 Subject: [PATCH 022/717] Remove extra blank line Satisfy linter --- .../Models/DiscordConnectionStringBuilder.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Tgstation.Server.Api/Models/DiscordConnectionStringBuilder.cs b/src/Tgstation.Server.Api/Models/DiscordConnectionStringBuilder.cs index 7ab64442ce8..0da207aa97c 100644 --- a/src/Tgstation.Server.Api/Models/DiscordConnectionStringBuilder.cs +++ b/src/Tgstation.Server.Api/Models/DiscordConnectionStringBuilder.cs @@ -34,7 +34,6 @@ public sealed class DiscordConnectionStringBuilder : ChatConnectionStringBuilder /// readonly bool unusedFlag; - /// /// Initializes a new instance of the class. /// From 40a0f9f82412344a37ae045d313158cab7b8d288 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 25 Aug 2023 10:43:23 -0400 Subject: [PATCH 023/717] Workaround for https://github.com/github/vscode-github-actions/issues/222 --- .github/workflows/ci-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index c2ff26e588b..76083813677 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -986,7 +986,7 @@ jobs: rm private.pgp - name: Install dotnet-sdk system package - if: "!contains(env.TGS_DOTNET_QUALITY, 'preview')" + if: (!contains(env.TGS_DOTNET_QUALITY, 'preview')) run: | sudo apt-get update sudo apt-get install -y dotnet-sdk-${{ env.TGS_DOTNET_VERSION }}.0 From e5e6121b9e8cd5b778e1d5a463e4634da48b7533 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 7 Oct 2023 13:48:00 -0400 Subject: [PATCH 024/717] Initial update to .NET 8 RC1 --- build/Version.props | 2 +- .../Tgstation.Server.Host.Console.csproj | 2 +- .../Tgstation.Server.Host.Service.csproj | 8 ++++---- .../Tgstation.Server.Host.Watchdog.csproj | 2 +- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 10 +++++----- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/build/Version.props b/build/Version.props index 79eeea43e77..782ee29423f 100644 --- a/build/Version.props +++ b/build/Version.props @@ -17,7 +17,7 @@ netstandard2.0 8 - https://download.visualstudio.microsoft.com/download/pr/e465df26-2f50-432f-a588-51c7682fd9b1/9efca17f575afd387aa9b02fb3dfb7e1/dotnet-hosting-8.0.0-preview.7.23375.9-win.exe + https://download.visualstudio.microsoft.com/download/pr/f6fcf7ad-2ae2-4b26-97be-bfaff4e6d873/4005d9603269b7266bd156ad1393475c/dotnet-hosting-8.0.0-rc.1.23421.29-win.exe 10.11.5 https://ftp.osuosl.org/pub/mariadb//mariadb-10.11.5/winx64-packages/mariadb-10.11.5-winx64.msi 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 791ab81994a..4ff44fedb75 100644 --- a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj +++ b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj @@ -11,7 +11,7 @@ - + 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 bd59f9ea736..c9f9666e184 100644 --- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj +++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj @@ -19,15 +19,15 @@ - + - + - + - + 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 df0f2e69999..da8207e6a85 100644 --- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj +++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index e4611d46d0b..ae367b1b94a 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -75,9 +75,9 @@ - + - + @@ -115,11 +115,11 @@ - + - + - + From 818d2198252e1f3c13281a62739f6316b607528e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 7 Oct 2023 13:49:05 -0400 Subject: [PATCH 025/717] Address some analyzer issues --- build/analyzers.ruleset | 10 +++++----- .../Components/Chat/Providers/IrcProvider.cs | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/build/analyzers.ruleset b/build/analyzers.ruleset index 365db1e57f0..0c5a955227b 100644 --- a/build/analyzers.ruleset +++ b/build/analyzers.ruleset @@ -715,8 +715,8 @@ - - + + @@ -952,8 +952,8 @@ - - + + @@ -1043,4 +1043,4 @@ - \ No newline at end of file + diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index c94908a64f2..f9f7d5cd20f 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -498,7 +498,7 @@ await Task.Factory.StartNew( /// If this is a query message. void HandleMessage(IrcEventArgs e, bool isPrivate) { - if (e.Data.Nick.ToUpperInvariant() == client.Nickname.ToUpperInvariant()) + if (e.Data.Nick.Equals(client.Nickname, StringComparison.OrdinalIgnoreCase)) return; var username = e.Data.Nick; @@ -605,16 +605,16 @@ async Task SaslAuthenticate(CancellationToken cancellationToken) client.Login(nickname, nickname, 0, nickname); cancellationToken.ThrowIfCancellationRequested(); - // wait for the sasl ack or timeout - var recievedAck = false; - var recievedPlus = false; + // wait for the SASL ack or timeout + var receivedAck = false; + var receivedPlus = false; void AuthenticationDelegate(object sender, ReadLineEventArgs e) { if (e.Line.Contains("ACK :sasl", StringComparison.Ordinal)) - recievedAck = true; + receivedAck = true; else if (e.Line.Contains("AUTHENTICATE +", StringComparison.Ordinal)) - recievedPlus = true; + receivedPlus = true; } Logger.LogTrace("Performing handshake..."); @@ -626,14 +626,14 @@ void AuthenticationDelegate(object sender, ReadLineEventArgs e) var timeoutToken = timeoutCts.Token; var listenTimeSpan = TimeSpan.FromMilliseconds(10); - for (; !recievedAck; + for (; !receivedAck; await AsyncDelayer.Delay(listenTimeSpan, timeoutToken)) await NonBlockingListen(cancellationToken); client.WriteLine("AUTHENTICATE PLAIN", Priority.Critical); timeoutToken.ThrowIfCancellationRequested(); - for (; !recievedPlus; + for (; !receivedPlus; await AsyncDelayer.Delay(listenTimeSpan, timeoutToken)) await NonBlockingListen(cancellationToken); } From 5c823420c207498554ca4e038de5293e5a28b369 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 7 Oct 2023 13:52:39 -0400 Subject: [PATCH 026/717] Update EFCore to .NET 8 RC1 --- .../.config/dotnet-tools.json | 2 +- .../Tgstation.Server.Host.csproj | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Tgstation.Server.Host/.config/dotnet-tools.json b/src/Tgstation.Server.Host/.config/dotnet-tools.json index c418dc80b94..2013d181bd4 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": "7.0.11", + "version": "8.0.0-rc.1.23419.6", "commands": [ "dotnet-ef" ] diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index ae367b1b94a..81016310398 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -79,25 +79,25 @@ - + - + runtime; build; native; contentfiles; analyzers; buildtransitive - + - + - + - + @@ -121,7 +121,7 @@ - + From 85c053dedca143186e3b12eab759579f4c6870f8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 7 Oct 2023 17:46:15 -0400 Subject: [PATCH 027/717] Fix version references to setup-dotnet --- .github/workflows/ci-pipeline.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 16f40a976d8..fa36ff55eb4 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -171,7 +171,7 @@ jobs: if: (!(cancelled() || failure()) && needs.start-ci-run-gate.result == 'success') steps: - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: dotnet-version: ${{ env.TGS_DOTNET_VERSION }} @@ -1259,7 +1259,7 @@ jobs: if: (!(cancelled() || failure()) && needs.deployment-gate.result == 'success' && contains(github.event.head_commit.message, '[APIDeploy]')) steps: - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: dotnet-version: ${{ env.TGS_DOTNET_VERSION }} @@ -1322,7 +1322,7 @@ jobs: if: (!(cancelled() || failure()) && needs.deployment-gate.result == 'success' && contains(github.event.head_commit.message, '[DMDeploy]')) steps: - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: dotnet-version: ${{ env.TGS_DOTNET_VERSION }} From 6e015f86faeeff983d3e0f7e2c9e486637ee7a31 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 9 Oct 2023 13:03:00 -0400 Subject: [PATCH 028/717] WIP OpenDream Support --- src/DMAPI/tgs.dm | 11 +- src/Tgstation.Server.Api/Models/EngineType.cs | 18 ++ .../Models/Internal/ByondVersion.cs | 109 ++++++++++++ .../Request/ByondVersionDeleteRequest.cs | 9 +- .../Models/Request/ByondVersionRequest.cs | 15 +- .../Models/Response/ByondResponse.cs | 15 +- .../Models/Response/CompileJobResponse.cs | 13 +- .../Rights/ByondRights.cs | 26 ++- .../Components/Byond/ByondExecutableLock.cs | 28 --- .../Components/Byond/ByondInstallation.cs | 130 ++++++++++++-- .../Components/Byond/ByondInstallerBase.cs | 19 +- .../Components/Byond/ByondManager.cs | 166 +++++++++++------- .../Components/Byond/EngineExecutableLock.cs | 49 ++++++ .../Components/Byond/IByondInstallation.cs | 35 ---- .../Components/Byond/IByondInstaller.cs | 31 ++-- .../Components/Byond/IByondManager.cs | 50 ++++-- ...utableLock.cs => IEngineExecutableLock.cs} | 2 +- .../Components/Byond/IEngineInstallation.cs | 65 +++++++ .../Components/Byond/OpenDreamInstallation.cs | 67 +++++++ .../Components/Byond/PosixByondInstaller.cs | 17 +- .../Components/Byond/WindowsByondInstaller.cs | 23 +-- .../Components/Chat/ChatManager.cs | 2 +- .../Components/Chat/Commands/ByondCommand.cs | 48 +++-- .../Components/Chat/IChatManager.cs | 4 +- .../Chat/Providers/DiscordProvider.cs | 23 ++- .../Components/Chat/Providers/IProvider.cs | 7 +- .../Components/Chat/Providers/IrcProvider.cs | 7 +- .../Components/Chat/Providers/Provider.cs | 7 +- .../Components/Deployment/DmbFactory.cs | 10 +- .../Components/Deployment/DmbProvider.cs | 17 +- .../Components/Deployment/DreamMaker.cs | 83 +++++---- .../Components/Deployment/IDmbProvider.cs | 9 +- .../Deployment/SwappableDmbProvider.cs | 7 +- .../Deployment/TemporaryDmbProvider.cs | 11 +- .../Session/ISessionControllerFactory.cs | 4 +- .../Components/Session/SessionController.cs | 6 +- .../Session/SessionControllerFactory.cs | 112 ++++-------- .../Controllers/ByondController.cs | 114 +++++++----- .../Models/CompileJob.cs | 6 +- .../Rights/TestRights.cs | 2 +- .../TestApiClient.cs | 22 ++- .../Byond/TestPosixByondInstaller.cs | 20 ++- .../Security/TestAuthenticationContext.cs | 4 +- .../CachingFileDownloader.cs | 17 +- .../Live/DummyChatProvider.cs | 11 +- .../Live/Instance/ByondTest.cs | 118 +++++++++---- .../Live/Instance/InstanceTest.cs | 18 +- .../Live/Instance/WatchdogTest.cs | 32 ++-- .../Live/TestLiveServer.cs | 21 ++- tests/Tgstation.Server.Tests/TestDatabase.cs | 2 +- tests/Tgstation.Server.Tests/TestVersions.cs | 44 ++++- 51 files changed, 1152 insertions(+), 534 deletions(-) create mode 100644 src/Tgstation.Server.Api/Models/EngineType.cs create mode 100644 src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs delete mode 100644 src/Tgstation.Server.Host/Components/Byond/ByondExecutableLock.cs create mode 100644 src/Tgstation.Server.Host/Components/Byond/EngineExecutableLock.cs delete mode 100644 src/Tgstation.Server.Host/Components/Byond/IByondInstallation.cs rename src/Tgstation.Server.Host/Components/Byond/{IByondExecutableLock.cs => IEngineExecutableLock.cs} (80%) create mode 100644 src/Tgstation.Server.Host/Components/Byond/IEngineInstallation.cs create mode 100644 src/Tgstation.Server.Host/Components/Byond/OpenDreamInstallation.cs diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm index 6187a67825a..6d35cf6593e 100644 --- a/src/DMAPI/tgs.dm +++ b/src/DMAPI/tgs.dm @@ -1,6 +1,6 @@ // tgstation-server DMAPI -#define TGS_DMAPI_VERSION "6.5.3" +#define TGS_DMAPI_VERSION "6.6.0" // All functions and datums outside this document are subject to change with any version and should not be relied on. @@ -73,11 +73,11 @@ #define TGS_EVENT_REPO_MERGE_PULL_REQUEST 3 /// Before the repository makes a sychronize operation. Parameters: Absolute repostiory path. #define TGS_EVENT_REPO_PRE_SYNCHRONIZE 4 -/// Before a BYOND install operation begins. Parameters: [/datum/tgs_version] of the installing BYOND. +/// Before a BYOND install operation begins. Parameters: [/datum/tgs_version] of the installing BYOND, engine type of the installing BYOND. #define TGS_EVENT_BYOND_INSTALL_START 5 /// When a BYOND install operation fails. Parameters: Error message #define TGS_EVENT_BYOND_INSTALL_FAIL 6 -/// When the active BYOND version changes. Parameters: (Nullable) [/datum/tgs_version] of the current BYOND, [/datum/tgs_version] of the new BYOND. +/// When the active BYOND version changes. Parameters: (Nullable) [/datum/tgs_version] of the current BYOND, [/datum/tgs_version] of the new BYOND, engine type of the current BYOND, engine type of the new BYOND. #define TGS_EVENT_BYOND_ACTIVE_VERSION_CHANGE 7 /// When the compiler starts running. Parameters: Game directory path, origin commit SHA. #define TGS_EVENT_COMPILE_START 8 @@ -129,6 +129,11 @@ /// DreamDaemon Ultrasafe security level. #define TGS_SECURITY_ULTRASAFE 2 +/// The Build Your Own Net Dream engine. +#define TGS_ENGINE_TYPE_BYOND 0 +/// The OpenDream engine. +#define TGS_ENGINE_TYPE_OPENDREAM 1 + //REQUIRED HOOKS /** diff --git a/src/Tgstation.Server.Api/Models/EngineType.cs b/src/Tgstation.Server.Api/Models/EngineType.cs new file mode 100644 index 00000000000..67410c1d470 --- /dev/null +++ b/src/Tgstation.Server.Api/Models/EngineType.cs @@ -0,0 +1,18 @@ +namespace Tgstation.Server.Api.Models +{ + /// + /// The type of engine the codebase is using. + /// + public enum EngineType + { + /// + /// Build your own net dream, + /// + Byond, + + /// + /// The OpenDream BYOND reimplementation. + /// + OpenDream, + } +} diff --git a/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs b/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs new file mode 100644 index 00000000000..8526d159b62 --- /dev/null +++ b/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs @@ -0,0 +1,109 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Linq; + +namespace Tgstation.Server.Api.Models.Internal +{ + /// + /// Information about a Byond installation. + /// + public class ByondVersion : IEquatable + { + /// + /// The . + /// + [RequestOptions(FieldPresence.Required)] + public EngineType? Engine { get; set; } + + /// + /// The of the engine. + /// + [ResponseOptions] + public Version? Version { get; set; } + + /// + /// The git committish of the . On response, this will always be a commit SHA. + /// + [ResponseOptions] + [StringLength(Limits.MaximumCommitShaLength)] + public string? SourceCommittish { get; set; } + + /// + /// Parses a stringified . + /// + /// The input . + /// The output . + /// if parsing was successful, otherwise. + public static bool TryParse(string input, out ByondVersion? byondVersion) + { + if (input == null) + throw new ArgumentNullException(nameof(input)); + + var splits = input.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries); + byondVersion = null; + + if (splits.Length > 2) + return false; + + EngineType engine; + if (splits.Length > 1) + { + if (!Enum.TryParse(splits[0], out engine)) + return false; + } + else + engine = EngineType.Byond; + + if (!Version.TryParse(splits.Last(), out var version)) + return false; + + byondVersion = new ByondVersion + { + Engine = engine, + Version = version, + }; + return true; + } + + /// + /// Initializes a new instance of the class. + /// + public ByondVersion() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The to copy. + public ByondVersion(ByondVersion other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + Version = other.Version; + Engine = other.Engine; + SourceCommittish = other.SourceCommittish; + } + + /// + public bool Equals(ByondVersion other) + { + // https://github.com/dotnet/roslyn-analyzers/issues/2875 +#pragma warning disable CA1062 // Validate arguments of public methods + return other!.Version == Version + && other.Engine == Engine; +#pragma warning restore CA1062 // Validate arguments of public methods + } + + /// + public override bool Equals(object obj) + => obj is ByondVersion other && Equals(other); + + /// + public override string ToString() => $"{(Engine != EngineType.Byond ? $"{Engine}-" : String.Empty)}{Version}"; // BYOND isn't display for backwards compatibility. SourceCommittish is not included + + /// + public override int GetHashCode() => ToString().GetHashCode(); + } +} diff --git a/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs b/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs index aaf8585c9be..ad5eac45ccd 100644 --- a/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs @@ -1,16 +1,13 @@ using System; +using Tgstation.Server.Api.Models.Internal; + namespace Tgstation.Server.Api.Models.Request { /// /// A request to delete a specific . /// - public class ByondVersionDeleteRequest + public class ByondVersionDeleteRequest : ByondVersion { - /// - /// The BYOND version to install. - /// - [RequestOptions(FieldPresence.Required)] - public Version? Version { get; set; } } } diff --git a/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs b/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs index b86eea074a9..a04dfd0d7e1 100644 --- a/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs @@ -1,13 +1,22 @@ -namespace Tgstation.Server.Api.Models.Request +using System; + +using Tgstation.Server.Api.Models.Internal; + +namespace Tgstation.Server.Api.Models.Request { /// - /// A request to install a BYOND . + /// A request to install a . /// - public sealed class ByondVersionRequest : ByondVersionDeleteRequest + public sealed class ByondVersionRequest : ByondVersion { /// /// If a custom BYOND version is to be uploaded. /// public bool? UploadCustomZip { get; set; } + + /// + /// The remote repository for non- s. By default, this is the original git repository of the target . + /// + public Uri? SourceRepository { get; set; } } } diff --git a/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs b/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs index 64b01090d53..92d524728da 100644 --- a/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs @@ -1,16 +1,19 @@ -using System; +using Tgstation.Server.Api.Models.Internal; namespace Tgstation.Server.Api.Models.Response { /// - /// Represents an installed BYOND . + /// Represents an installed . /// - public sealed class ByondResponse + public sealed class ByondResponse : ByondVersion { /// - /// The installed BYOND . BYOND itself only considers the and numbers. TGS uses the number to represent installed custom versions. + /// Initializes a new instance of the class. /// - [ResponseOptions] - public Version? Version { get; set; } + /// The to copy. + public ByondResponse(ByondVersion byondVersion) + : base(byondVersion) + { + } } } diff --git a/src/Tgstation.Server.Api/Models/Response/CompileJobResponse.cs b/src/Tgstation.Server.Api/Models/Response/CompileJobResponse.cs index 60444d9c3c9..a349710f077 100644 --- a/src/Tgstation.Server.Api/Models/Response/CompileJobResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/CompileJobResponse.cs @@ -1,9 +1,11 @@ using System; +using Tgstation.Server.Api.Models.Internal; + namespace Tgstation.Server.Api.Models.Response { /// - public sealed class CompileJobResponse : Internal.CompileJob + public sealed class CompileJobResponse : CompileJob { /// /// The relating to this job. @@ -16,9 +18,14 @@ public sealed class CompileJobResponse : Internal.CompileJob public RevisionInformation? RevisionInformation { get; set; } /// - /// The the was made with. + /// The the was made with. + /// + public ByondVersion? ByondVersion { get; set; } + + /// + /// The the was made with. /// - public Version? ByondVersion { get; set; } + public EngineType? Engine { get; set; } /// /// The origin of the repository the compile job was built from. diff --git a/src/Tgstation.Server.Api/Rights/ByondRights.cs b/src/Tgstation.Server.Api/Rights/ByondRights.cs index 288d8ca3b8d..6e20a62b3b5 100644 --- a/src/Tgstation.Server.Api/Rights/ByondRights.cs +++ b/src/Tgstation.Server.Api/Rights/ByondRights.cs @@ -14,33 +14,43 @@ public enum ByondRights : ulong None = 0, /// - /// User may view the active installed BYOND version. + /// User may view the active installed engine versions. /// ReadActive = 1 << 0, /// - /// User may list all installed BYOND versions. + /// User may list all installed engine versions. /// ListInstalled = 1 << 1, /// - /// User may install official BYOND versions or change the active BYOND version. + /// User may install official versions or change the active version. /// - InstallOfficialOrChangeActiveVersion = 1 << 2, + InstallOfficialOrChangeActiveByondVersion = 1 << 2, /// - /// User may cancel BYOND installation job. + /// User may cancel an engine installation job. /// CancelInstall = 1 << 3, /// - /// User may upload and activate custom BYOND builds. + /// User may upload and activate custom builds. /// - InstallCustomVersion = 1 << 4, + InstallCustomByondVersion = 1 << 4, /// - /// User may delete non-active BYOND builds. + /// User may delete non-active engine builds. /// DeleteInstall = 1 << 5, + + /// + /// User may install official versions or change the active version. + /// + InstallOfficialOrChangeActiveOpenDreamVersion = 1 << 6, + + /// + /// User may activate custom builds via zip upload or custom git committish. + /// + InstallCustomOpenDreamVersion = 1 << 7, } } diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondExecutableLock.cs b/src/Tgstation.Server.Host/Components/Byond/ByondExecutableLock.cs deleted file mode 100644 index 334b3469ea1..00000000000 --- a/src/Tgstation.Server.Host/Components/Byond/ByondExecutableLock.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; - -using Tgstation.Server.Host.Utils; - -namespace Tgstation.Server.Host.Components.Byond -{ - /// - sealed class ByondExecutableLock : ReferenceCounter, IByondExecutableLock - { - /// - public Version Version => Instance.Version; - - /// - public string DreamDaemonPath => Instance.DreamDaemonPath; - - /// - public string DreamMakerPath => Instance.DreamMakerPath; - - /// - public bool SupportsCli => Instance.SupportsCli; - - /// - public bool SupportsMapThreads => Instance.SupportsMapThreads; - - /// - public void DoNotDeleteThisSession() => DangerousDropReference(); - } -} diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondInstallation.cs b/src/Tgstation.Server.Host/Components/Byond/ByondInstallation.cs index 8554190d0f6..35a7fd614f8 100644 --- a/src/Tgstation.Server.Host/Components/Byond/ByondInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Byond/ByondInstallation.cs @@ -1,54 +1,148 @@ using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; using System.Threading.Tasks; +using System.Web; + +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Components.Deployment; namespace Tgstation.Server.Host.Components.Byond { - /// - sealed class ByondInstallation : IByondInstallation + /// + /// Implementation of for . + /// + sealed class ByondInstallation : IEngineInstallation { /// - public Version Version { get; } + public ByondVersion Version { get; } + + /// + public string ServerExePath { get; } /// - public string DreamDaemonPath { get; } + public string CompilerExePath { get; } /// - public string DreamMakerPath { get; } + public bool PromptsForNetworkAccess { get; } /// - public bool SupportsCli { get; } + public bool HasStandardOutput { get; } /// - public bool SupportsMapThreads { get; } + public Task InstallationTask { get; } /// - /// The that completes when the BYOND version finished installing. + /// If map threads are supported by the . /// - public Task InstallationTask { get; } + readonly bool supportsMapThreads; + + /// + /// Change a given into the appropriate DreamDaemon command line word. + /// + /// The level to change. + /// A representation of the command line parameter. + static string SecurityWord(DreamDaemonSecurity securityLevel) + { + return securityLevel switch + { + DreamDaemonSecurity.Safe => "safe", + DreamDaemonSecurity.Trusted => "trusted", + DreamDaemonSecurity.Ultrasafe => "ultrasafe", + _ => throw new ArgumentOutOfRangeException(nameof(securityLevel), securityLevel, String.Format(CultureInfo.InvariantCulture, "Bad DreamDaemon security level: {0}", securityLevel)), + }; + } + + /// + /// Change a given into the appropriate DreamDaemon command line word. + /// + /// The level to change. + /// A representation of the command line parameter. + static string VisibilityWord(DreamDaemonVisibility visibility) + { + return visibility switch + { + DreamDaemonVisibility.Public => "public", + DreamDaemonVisibility.Private => "private", + DreamDaemonVisibility.Invisible => "invisible", + _ => throw new ArgumentOutOfRangeException(nameof(visibility), visibility, String.Format(CultureInfo.InvariantCulture, "Bad DreamDaemon visibility level: {0}", visibility)), + }; + } /// /// Initializes a new instance of the class. /// /// The value of . /// The value of . - /// The value of . - /// The value of . - /// The value of . - /// The value of . + /// The value of . + /// The value of . + /// If a CLI application is being used. + /// The value of . public ByondInstallation( Task installationTask, - Version version, + ByondVersion version, string dreamDaemonPath, string dreamMakerPath, bool supportsCli, bool supportsMapThreads) { InstallationTask = installationTask ?? throw new ArgumentNullException(nameof(installationTask)); + ArgumentNullException.ThrowIfNull(version); + + if (version.Engine.Value != EngineType.Byond) + throw new ArgumentException($"Invalid EngineType: {version.Engine.Value}", nameof(version)); + Version = version ?? throw new ArgumentNullException(nameof(version)); - DreamDaemonPath = dreamDaemonPath ?? throw new ArgumentNullException(nameof(dreamDaemonPath)); - DreamMakerPath = dreamMakerPath ?? throw new ArgumentNullException(nameof(dreamMakerPath)); - SupportsCli = supportsCli; - SupportsMapThreads = supportsMapThreads; + ServerExePath = dreamDaemonPath ?? throw new ArgumentNullException(nameof(dreamDaemonPath)); + CompilerExePath = dreamMakerPath ?? throw new ArgumentNullException(nameof(dreamMakerPath)); + HasStandardOutput = supportsCli; + PromptsForNetworkAccess = !supportsCli; + this.supportsMapThreads = supportsMapThreads; } + + /// + public string FormatServerArguments( + IDmbProvider dmbProvider, + IReadOnlyDictionary parameters, + DreamDaemonLaunchParameters launchParameters, + string logFilePath) + { + ArgumentNullException.ThrowIfNull(dmbProvider); + ArgumentNullException.ThrowIfNull(parameters); + ArgumentNullException.ThrowIfNull(launchParameters); + + var parametersString = String.Join('&', parameters.Select(kvp => $"{HttpUtility.UrlEncode(kvp.Key)}={HttpUtility.UrlEncode(kvp.Value)}")); + + if (!String.IsNullOrEmpty(launchParameters.AdditionalParameters)) + parametersString = $"{parametersString}&{launchParameters.AdditionalParameters}"; + + var arguments = String.Format( + CultureInfo.InvariantCulture, + "{0} -port {1} -ports 1-65535 {2}-close -verbose -{3} -{4}{5}{6}{7} -params \"{8}\"", + dmbProvider.DmbName, + launchParameters.Port.Value, + launchParameters.AllowWebClient.Value + ? "-webclient " + : String.Empty, + SecurityWord(launchParameters.SecurityLevel.Value), + VisibilityWord(launchParameters.Visibility.Value), + logFilePath != null + ? $" -logself -log {logFilePath}" + : String.Empty, // DD doesn't output anything if -logself is set??? + launchParameters.StartProfiler.Value + ? " -profile" + : String.Empty, + supportsMapThreads && launchParameters.MapThreads.Value != 0 + ? $" -map-threads {launchParameters.MapThreads.Value}" + : String.Empty, + parametersString); + return arguments; + } + + /// + public string FormatCompilerArguments(string dmePath) + => $"-clean \"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\""; } } diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs index 2478acdc1f7..8260eafffaa 100644 --- a/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; namespace Tgstation.Server.Host.Components.Byond @@ -24,10 +25,10 @@ abstract class ByondInstallerBase : IByondInstaller public static Version MapThreadsVersion => new (515, 1609); /// - public abstract string DreamMakerName { get; } + public abstract string CompilerName { get; } /// - public abstract string PathToUserByondFolder { get; } + public abstract string PathToUserFolder { get; } /// /// Gets the URL formatter string for downloading a byond version of {0:Major} {1:Minor}. @@ -63,7 +64,7 @@ protected ByondInstallerBase(IIOManager ioManager, IFileDownloader fileDownloade } /// - public abstract string GetDreamDaemonName(Version version, out bool supportsCli, out bool supportsMapThreads); + public abstract string GetDreamDaemonName(ByondVersion version, out bool supportsCli, out bool supportsMapThreads); /// public async Task CleanCache(CancellationToken cancellationToken) @@ -73,7 +74,7 @@ public async Task CleanCache(CancellationToken cancellationToken) Logger.LogDebug("Cleaning BYOND cache..."); await IOManager.DeleteDirectory( IOManager.ConcatPath( - PathToUserByondFolder, + PathToUserFolder, CacheDirectoryName), cancellationToken); } @@ -84,18 +85,18 @@ await IOManager.DeleteDirectory( } /// - public abstract ValueTask InstallByond(Version version, string path, CancellationToken cancellationToken); + public abstract ValueTask InstallByond(ByondVersion version, string path, CancellationToken cancellationToken); /// - public abstract ValueTask UpgradeInstallation(Version version, string path, CancellationToken cancellationToken); + public abstract ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken); /// - public async ValueTask DownloadVersion(Version version, CancellationToken cancellationToken) + public async ValueTask DownloadVersion(ByondVersion version, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(version); - Logger.LogTrace("Downloading BYOND version {major}.{minor}...", version.Major, version.Minor); - var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Major, version.Minor); + Logger.LogTrace("Downloading BYOND version {major}.{minor}...", version.Version.Major, version.Version.Minor); + var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Version.Major, version.Version.Minor); await using var download = fileDownloader.DownloadFile(new Uri(url), null); await using var buffer = new BufferedFileStreamProvider( diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs b/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs index 73fadec9874..3c6f06c3ad2 100644 --- a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs +++ b/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging; using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.IO; @@ -47,10 +48,10 @@ sealed class ByondManager : IByondManager const string ActiveVersionFileName = "ActiveVersion.txt"; /// - public Version ActiveVersion { get; private set; } + public ByondVersion ActiveVersion { get; private set; } /// - public IReadOnlyList InstalledVersions + public IReadOnlyList InstalledVersions { get { @@ -87,7 +88,7 @@ public IReadOnlyList InstalledVersions /// /// Map of byond s to s that complete when they are installed. /// - readonly Dictionary> installedVersions; + readonly Dictionary> installedVersions; /// /// The for changing or deleting the active BYOND version. @@ -103,11 +104,14 @@ public IReadOnlyList InstalledVersions /// Validates a given parameter. /// /// The to validate. - static void CheckVersionParameter(Version version) + static void CheckVersionParameter(ByondVersion version) { ArgumentNullException.ThrowIfNull(version); - if (version.Build == 0) + if (!version.Engine.HasValue) + throw new InvalidOperationException("version.Engine cannot be null!"); + + if (version.Version.Build == 0) throw new InvalidOperationException("version.Build cannot be 0!"); } @@ -125,7 +129,7 @@ public ByondManager(IIOManager ioManager, IByondInstaller byondInstaller, IEvent this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - installedVersions = new Dictionary>(); + installedVersions = new Dictionary>(); changeDeleteSemaphore = new SemaphoreSlim(1); activeVersionChanged = new TaskCompletionSource(); } @@ -136,7 +140,7 @@ public ByondManager(IIOManager ioManager, IByondInstaller byondInstaller, IEvent /// public async ValueTask ChangeVersion( JobProgressReporter progressReporter, - Version version, + ByondVersion version, Stream customVersionStream, bool allowInstallation, CancellationToken cancellationToken) @@ -154,7 +158,10 @@ public async ValueTask ChangeVersion( cancellationToken); // We reparse the version because it could be changed after a custom install. - version = installLock.Version; + version = new ByondVersion(version) + { + Version = installLock.Version.Version, + }; var stringVersion = version.ToString(); await ioManager.WriteAllBytes(ActiveVersionFileName, Encoding.UTF8.GetBytes(stringVersion), cancellationToken); @@ -177,7 +184,7 @@ await eventConsumer.HandleEvent( } /// - public async ValueTask UseExecutables(Version requiredVersion, string trustDmbFullPath, CancellationToken cancellationToken) + public async ValueTask UseExecutables(ByondVersion requiredVersion, string trustDmbFullPath, CancellationToken cancellationToken) { logger.LogTrace( "Acquiring lock on BYOND version {version}...", @@ -205,7 +212,7 @@ public async ValueTask UseExecutables(Version requiredVers } /// - public async ValueTask DeleteVersion(JobProgressReporter progressReporter, Version version, CancellationToken cancellationToken) + public async ValueTask DeleteVersion(JobProgressReporter progressReporter, ByondVersion version, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(progressReporter); @@ -213,15 +220,18 @@ public async ValueTask DeleteVersion(JobProgressReporter progressReporter, Versi logger.LogTrace("DeleteVersion {version}", version); - if (version == ActiveVersion) + if (version.Equals(ActiveVersion)) throw new JobException(ErrorCode.ByondCannotDeleteActiveVersion); - ReferenceCountingContainer container; + ReferenceCountingContainer container; lock (installedVersions) if (!installedVersions.TryGetValue(version, out container)) - return; // already "deleted" + { + logger.LogTrace("Version {version} already deleted.", version); + return; + } - logger.LogInformation("Deleting BYOND version {version}...", version); + logger.LogInformation("Deleting version {version}...", version); progressReporter.StageName = "Waiting for version to not be in use..."; while (true) { @@ -238,7 +248,7 @@ await Task.WhenAny( .WaitAsync(cancellationToken); if (containerTask.IsCompleted) - logger.LogTrace("All BYOND locks for {version} are gone", version); + logger.LogTrace("All locks for version {version} are gone", version); using (await SemaphoreSlimContext.Lock(changeDeleteSemaphore, cancellationToken)) { @@ -252,7 +262,7 @@ await Task.WhenAny( proceed = container.OnZeroReferences.IsCompleted; if (proceed) if (!installedVersions.TryGetValue(version, out var newerContainer)) - logger.LogWarning("Unable to remove BYOND installation {version} from list! Is there a duplicate job running?", version); + logger.LogWarning("Unable to remove engine installation {version} from list! Is there a duplicate job running?", version); else { if (container != newerContainer) @@ -291,6 +301,13 @@ await ioManager.DeleteFile( } } + /// + public async ValueTask EnsureEngineSource(Uri source, EngineType engine, CancellationToken cancellationToken) + { + await Task.Yield(); + throw new NotImplementedException(); + } + /// public async Task StartAsync(CancellationToken cancellationToken) { @@ -302,7 +319,7 @@ async ValueTask GetActiveVersion() var activeVersionBytesTask = GetActiveVersion(); - var byondDir = byondInstaller.PathToUserByondFolder; + var byondDir = byondInstaller.PathToUserFolder; if (byondDir != null) using (await SemaphoreSlimContext.Lock(UserFilesSemaphore, cancellationToken)) { @@ -328,7 +345,7 @@ await ioManager.DeleteFile( await ioManager.CreateDirectory(DefaultIOManager.CurrentDirectory, cancellationToken); var directories = await ioManager.GetDirectories(DefaultIOManager.CurrentDirectory, cancellationToken); - var installedVersionPaths = new Dictionary(); + var installedVersionPaths = new Dictionary(); async ValueTask ReadVersion(string path) { @@ -342,7 +359,7 @@ async ValueTask ReadVersion(string path) var bytes = await ioManager.ReadAllBytes(versionFile, cancellationToken); var text = Encoding.UTF8.GetString(bytes); - if (!Version.TryParse(text, out var version)) + if (!ByondVersion.TryParse(text, out var version)) { logger.LogWarning("Cleaning path with unparsable version file: {versionPath}", ioManager.ResolvePath(path)); await ioManager.DeleteDirectory(path, cancellationToken); // cleanup @@ -383,10 +400,10 @@ await ValueTaskExtensions.WhenAll( { var activeVersionString = Encoding.UTF8.GetString(activeVersionBytes); - Version activeVersion; + ByondVersion activeVersion; bool hasRequestedActiveVersion; lock (installedVersions) - hasRequestedActiveVersion = Version.TryParse(activeVersionString, out activeVersion) + hasRequestedActiveVersion = ByondVersion.TryParse(activeVersionString, out activeVersion) && installedVersions.ContainsKey(activeVersion); if (hasRequestedActiveVersion) @@ -403,46 +420,47 @@ await ValueTaskExtensions.WhenAll( public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; /// - /// Ensures a BYOND is installed if it isn't already. + /// Ensures a BYOND is installed if it isn't already. /// /// The optional for the operation. - /// The BYOND to install. + /// The to install. /// Custom zip file to use. Will cause a number to be added. /// If this BYOND version is required as part of a locking operation. - /// If an installation should be performed if the is not installed. If and an installation is required an will be thrown. + /// If an installation should be performed if the is not installed. If and an installation is required an will be thrown. /// The for the operation. - /// A resulting in the . - async ValueTask AssertAndLockVersion( + /// A resulting in the . + async ValueTask AssertAndLockVersion( JobProgressReporter progressReporter, - Version version, + ByondVersion byondVersion, Stream customVersionStream, bool neededForLock, bool allowInstallation, CancellationToken cancellationToken) { var ourTcs = new TaskCompletionSource(); - ByondInstallation installation; - ByondExecutableLock installLock; + IEngineInstallation installation; + EngineExecutableLock installLock; bool installedOrInstalling; + var byondEngine = byondVersion.Engine.Value == EngineType.Byond; lock (installedVersions) { - if (customVersionStream != null) + if (customVersionStream != null && byondEngine) { var customInstallationNumber = 1; do { - version = new Version(version.Major, version.Minor, customInstallationNumber++); + byondVersion.Version = new Version(byondVersion.Version.Major, byondVersion.Version.Minor, customInstallationNumber++); } - while (installedVersions.ContainsKey(version)); + while (installedVersions.ContainsKey(byondVersion)); } - installedOrInstalling = installedVersions.TryGetValue(version, out var installationContainer); + installedOrInstalling = installedVersions.TryGetValue(byondVersion, out var installationContainer); if (!installedOrInstalling) { if (!allowInstallation) - throw new InvalidOperationException($"BYOND version {version} not installed!"); + throw new InvalidOperationException($"BYOND version {byondVersion} not installed!"); - installationContainer = AddInstallationContainer(version, ourTcs.Task); + installationContainer = AddInstallationContainer(byondVersion, ourTcs.Task); } installation = installationContainer.Instance; @@ -457,7 +475,7 @@ async ValueTask AssertAndLockVersion( progressReporter.StageName = "Waiting for existing installation job..."; if (neededForLock && !installation.InstallationTask.IsCompleted) - logger.LogWarning("The required BYOND version ({version}) is not readily available! We will have to wait for it to install.", version); + logger.LogWarning("The required BYOND version ({version}) is not readily available! We will have to wait for it to install.", byondVersion); await installation.InstallationTask.WaitAsync(cancellationToken); return installLock; @@ -467,24 +485,24 @@ async ValueTask AssertAndLockVersion( try { if (customVersionStream != null) - logger.LogInformation("Installing custom BYOND version as {version}...", version); + logger.LogInformation("Installing custom BYOND version as {version}...", byondVersion); else if (neededForLock) { - if (version.Build > 0) + if (byondEngine && byondVersion.Version.Build > 0) throw new JobException(ErrorCode.ByondNonExistentCustomVersion); - logger.LogWarning("The required BYOND version ({version}) is not readily available! We will have to install it.", version); + logger.LogWarning("The required BYOND version ({version}) is not readily available! We will have to install it.", byondVersion); } else - logger.LogDebug("Requested BYOND version {version} not currently installed. Doing so now...", version); + logger.LogDebug("Requested BYOND version {version} not currently installed. Doing so now...", byondVersion); if (progressReporter != null) progressReporter.StageName = "Running event"; - var versionString = version.ToString(); + var versionString = byondVersion.ToString(); await eventConsumer.HandleEvent(EventType.ByondInstallStart, new List { versionString }, false, cancellationToken); - await InstallVersionFiles(progressReporter, version, customVersionStream, cancellationToken); + await InstallVersionFiles(progressReporter, byondVersion, customVersionStream, cancellationToken); ourTcs.SetResult(); } @@ -494,7 +512,7 @@ async ValueTask AssertAndLockVersion( await eventConsumer.HandleEvent(EventType.ByondInstallFail, new List { ex.Message }, false, cancellationToken); lock (installedVersions) - installedVersions.Remove(version); + installedVersions.Remove(byondVersion); ourTcs.SetException(ex); throw; @@ -513,11 +531,11 @@ async ValueTask AssertAndLockVersion( /// Installs the files for a given BYOND . /// /// The optional for the operation. - /// The BYOND being installed with the number set if appropriate. + /// The being installed with the number set if appropriate. /// Custom zip file to use. Will cause a number to be added. /// The for the operation. /// A representing the running operation. - async ValueTask InstallVersionFiles(JobProgressReporter progressReporter, Version version, Stream customVersionStream, CancellationToken cancellationToken) + async ValueTask InstallVersionFiles(JobProgressReporter progressReporter, ByondVersion version, Stream customVersionStream, CancellationToken cancellationToken) { var installFullPath = ioManager.ResolvePath(version.ToString()); async ValueTask DirectoryCleanup() @@ -585,32 +603,46 @@ await ioManager.WriteAllBytes( } /// - /// Create and add a new to . + /// Create and add a new to . /// /// The being added. /// The representing the installation process. - /// The new containing the new . - ReferenceCountingContainer AddInstallationContainer(Version version, Task installationTask) + /// The new containing the new . + ReferenceCountingContainer AddInstallationContainer(ByondVersion version, Task installationTask) { var binPathForVersion = ioManager.ConcatPath(version.ToString(), BinPath); - var installation = new ByondInstallation( - installationTask, - version, - ioManager.ResolvePath( - ioManager.ConcatPath( - binPathForVersion, - byondInstaller.GetDreamDaemonName( - version, - out var supportsCli, - out var supportsMapThreads))), - ioManager.ResolvePath( - ioManager.ConcatPath( - binPathForVersion, - byondInstaller.DreamMakerName)), - supportsCli, - supportsMapThreads); - - var installationContainer = new ReferenceCountingContainer(installation); + IEngineInstallation installation; + + switch (version.Engine.Value) + { + case EngineType.Byond: + installation = new ByondInstallation( + installationTask, + version, + ioManager.ResolvePath( + ioManager.ConcatPath( + binPathForVersion, + byondInstaller.GetDreamDaemonName( + version, + out var supportsCli, + out var supportsMapThreads))), + ioManager.ResolvePath( + ioManager.ConcatPath( + binPathForVersion, + byondInstaller.CompilerName)), + supportsCli, + supportsMapThreads); + break; + case EngineType.OpenDream: + installation = new OpenDreamInstallation( + installationTask, + version); + break; + default: + throw new InvalidOperationException($"Invalid EngineType: {version.Engine.Value}"); + } + + var installationContainer = new ReferenceCountingContainer(installation); lock (installedVersions) installedVersions.Add(version, installationContainer); @@ -626,7 +658,7 @@ ReferenceCountingContainer AddInstallati /// A representing the running operation. async ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken) { - var byondDir = byondInstaller.PathToUserByondFolder; + var byondDir = byondInstaller.PathToUserFolder; if (String.IsNullOrWhiteSpace(byondDir)) { logger.LogTrace("No relevant user BYOND directory to install a \"{fileName}\" in", TrustedDmbFileName); diff --git a/src/Tgstation.Server.Host/Components/Byond/EngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Byond/EngineExecutableLock.cs new file mode 100644 index 00000000000..9c3d2ebdfcf --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Byond/EngineExecutableLock.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.Utils; + +namespace Tgstation.Server.Host.Components.Byond +{ + /// + sealed class EngineExecutableLock : ReferenceCounter, IEngineExecutableLock + { + /// + public ByondVersion Version => Instance.Version; + + /// + public string ServerExePath => Instance.ServerExePath; + + /// + public string CompilerExePath => Instance.CompilerExePath; + + /// + public bool HasStandardOutput => Instance.HasStandardOutput; + + /// + public bool PromptsForNetworkAccess => Instance.PromptsForNetworkAccess; + + /// + public Task InstallationTask => Instance.InstallationTask; + + /// + public void DoNotDeleteThisSession() => DangerousDropReference(); + + /// + public string FormatServerArguments( + IDmbProvider dmbProvider, + IReadOnlyDictionary parameters, + DreamDaemonLaunchParameters launchParameters, + string logFilePath) + => Instance.FormatServerArguments( + dmbProvider, + parameters, + launchParameters, + logFilePath); + + /// + public string FormatCompilerArguments(string dmePath) => Instance.FormatCompilerArguments(dmePath); + } +} diff --git a/src/Tgstation.Server.Host/Components/Byond/IByondInstallation.cs b/src/Tgstation.Server.Host/Components/Byond/IByondInstallation.cs deleted file mode 100644 index 52a4e694b71..00000000000 --- a/src/Tgstation.Server.Host/Components/Byond/IByondInstallation.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; - -namespace Tgstation.Server.Host.Components.Byond -{ - /// - /// Represents a BYOND installation. - /// - public interface IByondInstallation - { - /// - /// The of the . - /// - Version Version { get; } - - /// - /// The full path to the DreamDaemon executable. - /// - string DreamDaemonPath { get; } - - /// - /// The full path to the dm/DreamMaker executable. - /// - string DreamMakerPath { get; } - - /// - /// If supports being run as a command-line application. - /// - bool SupportsCli { get; } - - /// - /// If supports the -map-threads parameter. - /// - bool SupportsMapThreads { get; } - } -} diff --git a/src/Tgstation.Server.Host/Components/Byond/IByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/IByondInstaller.cs index 9c353378303..b1a89bd48ce 100644 --- a/src/Tgstation.Server.Host/Components/Byond/IByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/IByondInstaller.cs @@ -1,8 +1,9 @@ -using System; -using System.IO; +using System.IO; using System.Threading; using System.Threading.Tasks; +using Tgstation.Server.Api.Models.Internal; + namespace Tgstation.Server.Host.Components.Byond { /// @@ -11,52 +12,52 @@ namespace Tgstation.Server.Host.Components.Byond interface IByondInstaller { /// - /// Get the file name of the DreamMaker executable. + /// Get the file name of the compiler executable. /// - string DreamMakerName { get; } + string CompilerName { get; } /// - /// The path to the BYOND folder for the user. + /// The path to the folder for the user's data. /// - string PathToUserByondFolder { get; } + string PathToUserFolder { get; } /// /// Get the file name of the DreamDaemon executable. /// - /// The of BYOND to select the executable name for. + /// The of BYOND to select the executable name for. /// Whether or not the returned path supports being run as a command-line application. /// Whether or not the returned path supports the '-map-threads' parameter. /// The file name of the DreamDaemon executable. - string GetDreamDaemonName(Version version, out bool supportsCli, out bool supportsMapThreads); + string GetDreamDaemonName(ByondVersion version, out bool supportsCli, out bool supportsMapThreads); /// /// Download a given BYOND . /// - /// The of BYOND to download. + /// The of BYOND to download. /// The for the operation. /// A resulting in a of the zipfile. - ValueTask DownloadVersion(Version version, CancellationToken cancellationToken); + ValueTask DownloadVersion(ByondVersion version, CancellationToken cancellationToken); /// /// Does actions necessary to get an extracted BYOND installation working. /// - /// The of BYOND being installed. + /// The being installed. /// The path to the BYOND installation. /// The for the operation. /// A representing the running operation. - ValueTask InstallByond(Version version, string path, CancellationToken cancellationToken); + ValueTask InstallByond(ByondVersion version, string path, CancellationToken cancellationToken); /// /// Does actions necessary to get upgrade a BYOND version installed by a previous version of TGS. /// - /// The of BYOND being installed. + /// The being installed. /// The path to the BYOND installation. /// The for the operation. /// A representing the running operation. - ValueTask UpgradeInstallation(Version version, string path, CancellationToken cancellationToken); + ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken); /// - /// Attempts to cleans the BYOND cache folder for the system. + /// Attempts to cleans the engine's cache folder for the system. /// /// The for the operation. /// A representing the running operation. diff --git a/src/Tgstation.Server.Host/Components/Byond/IByondManager.cs b/src/Tgstation.Server.Host/Components/Byond/IByondManager.cs index 092034b1c0b..1da8c041d16 100644 --- a/src/Tgstation.Server.Host/Components/Byond/IByondManager.cs +++ b/src/Tgstation.Server.Host/Components/Byond/IByondManager.cs @@ -4,6 +4,8 @@ using System.Threading; using System.Threading.Tasks; +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Jobs; namespace Tgstation.Server.Host.Components.Byond @@ -11,48 +13,62 @@ namespace Tgstation.Server.Host.Components.Byond /// /// For managing the BYOND installation. /// - /// When passing in s, ensure they are BYOND format versions unless referring to a custom version. This means should NEVER be 0. + /// When passing in s for , ensure they are BYOND format versions unless referring to a custom version. This means should NEVER be 0. public interface IByondManager : IComponentService, IDisposable { /// - /// The currently active BYOND version. + /// The currently active . /// - Version ActiveVersion { get; } + ByondVersion ActiveVersion { get; } /// - /// The installed BYOND versions. + /// The installed s. /// - IReadOnlyList InstalledVersions { get; } + IReadOnlyList InstalledVersions { get; } /// - /// Change the active BYOND version. + /// Ensure that the given is registered for the given . + /// + /// The source of the . + /// The . + /// The for the operation. + /// A representing the running operation. + ValueTask EnsureEngineSource(Uri source, EngineType engine, CancellationToken cancellationToken); + + /// + /// Change the active . /// /// The optional for the operation. - /// The new . + /// The new . /// Optional of a custom BYOND version zip file. /// If an installation should be performed if the is not installed. If and an installation is required an will be thrown. /// The for the operation. /// A representing the running operation. - ValueTask ChangeVersion(JobProgressReporter progressReporter, Version version, Stream customVersionStream, bool allowInstallation, CancellationToken cancellationToken); + ValueTask ChangeVersion( + JobProgressReporter progressReporter, + ByondVersion version, + Stream customVersionStream, + bool allowInstallation, + CancellationToken cancellationToken); /// - /// Deletes a given BYOND version from the disk. + /// Deletes a given from the disk. /// /// The for the operation. - /// The to delete. + /// The to delete. /// The for the operation. - /// A representing the running operation. - ValueTask DeleteVersion(JobProgressReporter progressReporter, Version version, CancellationToken cancellationToken); + /// A representing the running operation. + ValueTask DeleteVersion(JobProgressReporter progressReporter, ByondVersion version, CancellationToken cancellationToken); /// - /// Lock the current installation's location and return a . + /// Lock the current installation's location and return a . /// - /// The BYOND required. + /// The required. /// The optional full path to .dmb to trust while using the executables. /// The for the operation. - /// A resulting in the requested . - ValueTask UseExecutables( - Version requiredVersion, + /// A resulting in the requested . + ValueTask UseExecutables( + ByondVersion requiredVersion, string trustDmbFullPath, CancellationToken cancellationToken); } diff --git a/src/Tgstation.Server.Host/Components/Byond/IByondExecutableLock.cs b/src/Tgstation.Server.Host/Components/Byond/IEngineExecutableLock.cs similarity index 80% rename from src/Tgstation.Server.Host/Components/Byond/IByondExecutableLock.cs rename to src/Tgstation.Server.Host/Components/Byond/IEngineExecutableLock.cs index a320109dce0..ae3ad5d4383 100644 --- a/src/Tgstation.Server.Host/Components/Byond/IByondExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/Byond/IEngineExecutableLock.cs @@ -5,7 +5,7 @@ namespace Tgstation.Server.Host.Components.Byond /// /// Represents usage of the two primary BYOND server executables. /// - public interface IByondExecutableLock : IByondInstallation, IDisposable + public interface IEngineExecutableLock : IEngineInstallation, IDisposable { /// /// Call if, during a detach, this version should not be deleted. diff --git a/src/Tgstation.Server.Host/Components/Byond/IEngineInstallation.cs b/src/Tgstation.Server.Host/Components/Byond/IEngineInstallation.cs new file mode 100644 index 00000000000..39c29b547a3 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Byond/IEngineInstallation.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Components.Deployment; + +namespace Tgstation.Server.Host.Components.Byond +{ + /// + /// Represents a BYOND installation. + /// + public interface IEngineInstallation + { + /// + /// The of the . + /// + ByondVersion Version { get; } + + /// + /// The full path to the game server executable. + /// + string ServerExePath { get; } + + /// + /// The full path to the dm/DreamMaker executable. + /// + string CompilerExePath { get; } + + /// + /// If supports being run as a command-line application and outputs log information to be captured. + /// + bool HasStandardOutput { get; } + + /// + /// If may create network prompts. + /// + bool PromptsForNetworkAccess { get; } + + /// + /// The that completes when the BYOND version finished installing. + /// + Task InstallationTask { get; } + + /// + /// Return the command line arguments for launching with given . + /// + /// The . + /// The map of parameter s as a . Should NOT include the of . + /// The . + /// The path to the log file, if any. + /// The formatted arguments . + string FormatServerArguments( + IDmbProvider dmbProvider, + IReadOnlyDictionary parameters, + DreamDaemonLaunchParameters launchParameters, + string logFilePath); + + /// + /// Return the command line arguments for compiling a given if compilation is necessary. + /// + /// The full path to the .dme to compile. + /// An arguments if compilation is required, otherwise. + string FormatCompilerArguments(string dmePath); + } +} diff --git a/src/Tgstation.Server.Host/Components/Byond/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Byond/OpenDreamInstallation.cs new file mode 100644 index 00000000000..a7df3ddc286 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Byond/OpenDreamInstallation.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Components.Deployment; + +namespace Tgstation.Server.Host.Components.Byond +{ + /// + /// Implementation of for . + /// + sealed class OpenDreamInstallation : IEngineInstallation + { + /// + public ByondVersion Version { get; } + + /// + public string ServerExePath { get; } + + /// + public string CompilerExePath { get; } + + /// + public bool PromptsForNetworkAccess => false; + + /// + public bool HasStandardOutput => true; + + /// + public Task InstallationTask { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + public OpenDreamInstallation( + Task installationTask, + ByondVersion version) + { + InstallationTask = installationTask ?? throw new ArgumentNullException(nameof(installationTask)); + ArgumentNullException.ThrowIfNull(version); + + if (version.Engine.Value != EngineType.OpenDream) + throw new ArgumentException($"Invalid EngineType: {version.Engine.Value}", nameof(version)); + + Version = version ?? throw new ArgumentNullException(nameof(version)); + + throw new NotImplementedException(); + } + + /// + public string FormatServerArguments(IDmbProvider dmbProvider, IReadOnlyDictionary parameters, DreamDaemonLaunchParameters launchParameters, string logFilePath) + { + throw new NotImplementedException(); + } + + /// + public string FormatCompilerArguments(string dmePath) + { + ArgumentNullException.ThrowIfNull(dmePath); + return null; + } + } +} diff --git a/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs index 3657e015d47..7fed2498ec4 100644 --- a/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.IO; @@ -32,10 +33,10 @@ sealed class PosixByondInstaller : ByondInstallerBase const string ShellScriptExtension = ".sh"; /// - public override string DreamMakerName => DreamMakerExecutableName + ShellScriptExtension; + public override string CompilerName => DreamMakerExecutableName + ShellScriptExtension; /// - public override string PathToUserByondFolder { get; } + public override string PathToUserFolder { get; } /// protected override string ByondRevisionsUrlTemplate => "https://www.byond.com/download/build/{0}/{0}.{1}_byond_linux.zip"; @@ -61,7 +62,7 @@ public PosixByondInstaller( { this.postWriteHandler = postWriteHandler ?? throw new ArgumentNullException(nameof(postWriteHandler)); - PathToUserByondFolder = IOManager.ResolvePath( + PathToUserFolder = IOManager.ResolvePath( IOManager.ConcatPath( Environment.GetFolderPath( Environment.SpecialFolder.UserProfile), @@ -69,17 +70,17 @@ public PosixByondInstaller( } /// - public override string GetDreamDaemonName(Version version, out bool supportsCli, out bool supportsMapThreads) + public override string GetDreamDaemonName(ByondVersion version, out bool supportsCli, out bool supportsMapThreads) { ArgumentNullException.ThrowIfNull(version); supportsCli = true; - supportsMapThreads = version >= MapThreadsVersion; + supportsMapThreads = version.Version >= MapThreadsVersion; return DreamDaemonExecutableName + ShellScriptExtension; } /// - public override ValueTask InstallByond(Version version, string path, CancellationToken cancellationToken) + public override ValueTask InstallByond(ByondVersion version, string path, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(version); ArgumentNullException.ThrowIfNull(path); @@ -105,7 +106,7 @@ async ValueTask WriteAndMakeExecutable(string pathToScript, string script) dreamDaemonScript); var dmTask = WriteAndMakeExecutable( - IOManager.ConcatPath(basePath, DreamMakerName), + IOManager.ConcatPath(basePath, CompilerName), dreamMakerScript); var task = ValueTaskExtensions.WhenAll( @@ -119,7 +120,7 @@ async ValueTask WriteAndMakeExecutable(string pathToScript, string script) } /// - public override ValueTask UpgradeInstallation(Version version, string path, CancellationToken cancellationToken) + public override ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(version); ArgumentNullException.ThrowIfNull(path); diff --git a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs index 8080abc12ff..0b177584a4a 100644 --- a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Options; using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; @@ -53,10 +54,10 @@ sealed class WindowsByondInstaller : ByondInstallerBase, IDisposable public static Version DDExeVersion => new (515, 1598); /// - public override string DreamMakerName => "dm.exe"; + public override string CompilerName => "dm.exe"; /// - public override string PathToUserByondFolder { get; } + public override string PathToUserFolder { get; } /// protected override string ByondRevisionsUrlTemplate => "https://www.byond.com/download/build/{0}/{0}.{1}_byond.zip"; @@ -102,9 +103,9 @@ public WindowsByondInstaller( var documentsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); if (String.IsNullOrWhiteSpace(documentsDirectory)) - PathToUserByondFolder = null; // happens with the service account + PathToUserFolder = null; // happens with the service account else - PathToUserByondFolder = IOManager.ResolvePath(IOManager.ConcatPath(documentsDirectory, "BYOND")); + PathToUserFolder = IOManager.ResolvePath(IOManager.ConcatPath(documentsDirectory, "BYOND")); semaphore = new SemaphoreSlim(1); installedDirectX = false; @@ -114,17 +115,17 @@ public WindowsByondInstaller( public void Dispose() => semaphore.Dispose(); /// - public override string GetDreamDaemonName(Version version, out bool supportsCli, out bool supportsMapThreads) + public override string GetDreamDaemonName(ByondVersion version, out bool supportsCli, out bool supportsMapThreads) { ArgumentNullException.ThrowIfNull(version); - supportsCli = version >= DDExeVersion; - supportsMapThreads = version >= MapThreadsVersion; + supportsCli = version.Version >= DDExeVersion; + supportsMapThreads = version.Version >= MapThreadsVersion; return supportsCli ? "dd.exe" : "dreamdaemon.exe"; } /// - public override ValueTask InstallByond(Version version, string path, CancellationToken cancellationToken) + public override ValueTask InstallByond(ByondVersion version, string path, CancellationToken cancellationToken) { var tasks = new List(3) { @@ -139,7 +140,7 @@ public override ValueTask InstallByond(Version version, string path, Cancellatio } /// - public override async ValueTask UpgradeInstallation(Version version, string path, CancellationToken cancellationToken) + public override async ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(version); ArgumentNullException.ThrowIfNull(path); @@ -147,7 +148,7 @@ public override async ValueTask UpgradeInstallation(Version version, string path if (generalConfiguration.SkipAddingByondFirewallException) return; - if (version < DDExeVersion) + if (version.Version < DDExeVersion) return; if (await IOManager.FileExists(IOManager.ConcatPath(path, TgsFirewalledDDFile), cancellationToken)) @@ -227,7 +228,7 @@ async ValueTask InstallDirectX(string path, CancellationToken cancellationToken) /// The path to the BYOND installation. /// The for the operation. /// A representing the running operation. - async ValueTask AddDreamDaemonToFirewall(Version version, string path, CancellationToken cancellationToken) + async ValueTask AddDreamDaemonToFirewall(ByondVersion version, string path, CancellationToken cancellationToken) { var dreamDaemonName = GetDreamDaemonName(version, out var usesDDExe, out var _); diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index ecb0fa6498c..6bc1ddc015e 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -359,7 +359,7 @@ public void QueueWatchdogMessage(string message) /// public Func> QueueDeploymentMessage( Models.RevisionInformation revisionInformation, - Version byondVersion, + ByondVersion byondVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs index f0c87ef4df3..8f7b680293d 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs @@ -1,5 +1,4 @@ using System; -using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -49,20 +48,45 @@ public ByondCommand(IByondManager byondManager, IWatchdog watchdog) /// public ValueTask Invoke(string arguments, ChatUser user, CancellationToken cancellationToken) { - if (arguments.Split(' ').Any(x => x.ToUpperInvariant() == "--ACTIVE")) - return ValueTask.FromResult(new MessageContent - { - Text = byondManager.ActiveVersion == null ? "None!" : String.Format(CultureInfo.InvariantCulture, "{0}.{1}", byondManager.ActiveVersion.Major, byondManager.ActiveVersion.Minor), - }); + if (arguments.Split(' ').Any(x => x.Equals("--active", StringComparison.OrdinalIgnoreCase))) + { + string text; + if (byondManager.ActiveVersion == null) + text = "None!"; + else + switch (byondManager.ActiveVersion.Engine.Value) + { + case EngineType.OpenDream: + text = $"OpenDream: {byondManager.ActiveVersion.SourceCommittish}"; + break; + case EngineType.Byond: + text = $"BYOND {byondManager.ActiveVersion.Version.Major}.{byondManager.ActiveVersion.Version.Minor}"; + if (byondManager.ActiveVersion.Version.Build != -1) + text += " (Custom Build)"; + + break; + default: + throw new InvalidOperationException($"Invalid EngineType: {byondManager.ActiveVersion.Engine.Value}"); + } + + return ValueTask.FromResult( + new MessageContent + { + Text = text, + }); + } + if (watchdog.Status == WatchdogStatus.Offline) - return ValueTask.FromResult(new MessageContent + return ValueTask.FromResult( + new MessageContent + { + Text = "Server offline!", + }); + return ValueTask.FromResult( + new MessageContent { - Text = "Server offline!", + Text = watchdog.ActiveCompileJob?.ByondVersion ?? "None!", }); - return ValueTask.FromResult(new MessageContent - { - Text = watchdog.ActiveCompileJob?.ByondVersion ?? "None!", - }); } } } diff --git a/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs index 769ab7b2515..3f21930cf5a 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs @@ -61,7 +61,7 @@ public interface IChatManager : IComponentService, IAsyncDisposable /// Send the message for a deployment to configured deployment channels. /// /// The of the deployment. - /// The BYOND of the deployment. + /// The of the deployment. /// The optional the deployment is expected to be completed at. /// The repository GitHub owner, if any. /// The repository GitHub name, if any. @@ -69,7 +69,7 @@ public interface IChatManager : IComponentService, IAsyncDisposable /// A to call to update the message at the deployment's conclusion. Parameters: Error message if any, DreamMaker output if any. Returns an to call to mark the deployment as active/inactive. Parameter: If the deployment is being activated or inactivated. Func> QueueDeploymentMessage( Models.RevisionInformation revisionInformation, - Version byondVersion, + ByondVersion byondVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index bba9673ecf0..492eb8e332f 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -22,6 +22,7 @@ using Remora.Results; using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Extensions; @@ -129,25 +130,35 @@ public override string BotMention /// Create a of s for a discord update embed. /// /// The of the deployment. - /// The BYOND of the deployment. + /// The of the deployment. /// The repository GitHub owner, if any. /// The repository GitHub name, if any. /// if the local deployment commit was pushed to the remote repository. /// A new of s to use. static List BuildUpdateEmbedFields( Models.RevisionInformation revisionInformation, - Version byondVersion, + ByondVersion byondVersion, string gitHubOwner, string gitHubRepo, bool localCommitPushed) { bool gitHub = gitHubOwner != null && gitHubRepo != null; - var fields = new List + var engineField = byondVersion.Engine.Value switch { - new EmbedField( + EngineType.Byond => new EmbedField( "BYOND Version", - $"{byondVersion.Major}.{byondVersion.Minor}{(byondVersion.Build > 0 ? $".{byondVersion.Build}" : String.Empty)}", + $"{byondVersion.Version.Major}.{byondVersion.Version.Minor}{(byondVersion.Version.Build > 0 ? $".{byondVersion.Version.Build}" : String.Empty)}", true), + EngineType.OpenDream => new EmbedField( + "OpenDream Version", + $"[{byondVersion.SourceCommittish[..7]}](https://github.com/OpenDreamProject/OpenDream/commit/{revisionInformation.CommitSha})", + true), + _ => throw new InvalidOperationException($"Invaild EngineType: {byondVersion.Engine.Value}"), + }; + + var fields = new List + { + engineField, new EmbedField( "Local Commit", localCommitPushed && gitHub @@ -323,7 +334,7 @@ await ValueTaskExtensions.WhenAll( /// public override async ValueTask>>> SendUpdateMessage( Models.RevisionInformation revisionInformation, - Version byondVersion, + ByondVersion byondVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs index 641372c3180..489d8f42880 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Models; @@ -83,7 +84,7 @@ interface IProvider : IAsyncDisposable /// Send the message for a deployment. /// /// The of the deployment. - /// The BYOND of the deployment. + /// The of the deployment. /// The optional the deployment is expected to be completed at. /// The repository GitHub owner, if any. /// The repository GitHub name, if any. @@ -92,8 +93,8 @@ interface IProvider : IAsyncDisposable /// The for the operation. /// A resulting in a to call to update the message at the deployment's conclusion. Parameters: Error message if any, DreamMaker output if any. Returns another callback which should be called to mark the deployment as active. ValueTask>>> SendUpdateMessage( - RevisionInformation revisionInformation, - Version byondVersion, + Models.RevisionInformation revisionInformation, + ByondVersion byondVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index 605bad64b46..7cf73595c5b 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -12,6 +12,7 @@ using Newtonsoft.Json; using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; @@ -220,7 +221,7 @@ await Task.Factory.StartNew( /// public override async ValueTask>>> SendUpdateMessage( Models.RevisionInformation revisionInformation, - Version byondVersion, + ByondVersion byondVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, @@ -271,9 +272,7 @@ await SendMessage( commitInsert, testmergeInsert, remoteCommitInsert, - byondVersion.Build > 0 - ? byondVersion.ToString() - : $"{byondVersion.Major}.{byondVersion.Minor}", + byondVersion.ToString(), estimatedCompletionTime.HasValue ? $" ETA: {estimatedCompletionTime - DateTimeOffset.UtcNow}" : String.Empty), diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs index 88cd5b2e2c6..4cf04a8f32f 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Logging; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Rights; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Jobs; @@ -182,8 +183,8 @@ public Task SetReconnectInterval(uint reconnectInterval, bool connectNow) /// public abstract ValueTask>>> SendUpdateMessage( - RevisionInformation revisionInformation, - Version byondVersion, + Models.RevisionInformation revisionInformation, + ByondVersion byondVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, @@ -273,7 +274,7 @@ async Task ReconnectionLoop(uint reconnectInterval, bool connectNow, Cancellatio connectNow = false; if (!Connected) { - var job = new Job + var job = new Models.Job { Description = $"Reconnect chat bot: {ChatBot.Name}", CancelRight = (ulong)ChatBotRights.WriteEnabled, diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs index b4e333a41d5..e5e361299b8 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs @@ -245,6 +245,12 @@ await databaseContextFactory.UseContext( .ThenInclude(x => x.MergedBy) .FirstAsync(cancellationToken)); // can't wait to see that query + if (!Api.Models.Internal.ByondVersion.TryParse(compileJob.ByondVersion, out var byondVersion)) + { + logger.LogWarning("Error loading compile job, bad BYOND version: {0}", compileJob.ByondVersion); + return null; // omae wa mou shinderu + } + if (!compileJob.Job.StoppedAt.HasValue) { // This happens when we're told to load the compile job that is currently finished up @@ -262,7 +268,7 @@ void CleanupAction() CleanRegisteredCompileJob(compileJob); } - var newProvider = new DmbProvider(compileJob, ioManager, CleanupAction); + var newProvider = new DmbProvider(compileJob, byondVersion, ioManager, CleanupAction); try { const string LegacyADirectoryName = "A"; @@ -299,7 +305,7 @@ void CleanupAction() // rebuild the provider because it's using the legacy style directories // Don't dispose it logger.LogDebug("Creating legacy two folder .dmb provider targeting {aDirName} directory...", LegacyADirectoryName); - newProvider = new DmbProvider(compileJob, ioManager, CleanupAction, Path.DirectorySeparatorChar + LegacyADirectoryName); + newProvider = new DmbProvider(compileJob, byondVersion, ioManager, CleanupAction, Path.DirectorySeparatorChar + LegacyADirectoryName); } lock (jobLockCounts) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs index f3711ede4f8..554cc28cdd5 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs @@ -1,7 +1,7 @@ using System; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; -using Tgstation.Server.Host.Models; namespace Tgstation.Server.Host.Components.Deployment { @@ -14,10 +14,11 @@ sealed class DmbProvider : IDmbProvider /// public string Directory => ioManager.ResolvePath(CompileJob.DirectoryName.ToString() + directoryAppend); - /// - /// The for the . - /// - public CompileJob CompileJob { get; } + /// + public Models.CompileJob CompileJob { get; } + + /// + public ByondVersion ByondVersion { get; } /// /// The for the . @@ -25,7 +26,7 @@ sealed class DmbProvider : IDmbProvider readonly IIOManager ioManager; /// - /// Extra path to add to the end of . + /// Extra path to add to the end of . /// readonly string directoryAppend; @@ -38,12 +39,14 @@ sealed class DmbProvider : IDmbProvider /// Initializes a new instance of the class. /// /// The value of . + /// The value of . /// The value of . /// The value of . /// The optional value of . - public DmbProvider(CompileJob compileJob, IIOManager ioManager, Action onDispose, string directoryAppend = null) + public DmbProvider(Models.CompileJob compileJob, ByondVersion byondVersion, IIOManager ioManager, Action onDispose, string directoryAppend = null) { CompileJob = compileJob ?? throw new ArgumentNullException(nameof(compileJob)); + ByondVersion = byondVersion ?? throw new ArgumentNullException(nameof(byondVersion)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.onDispose = onDispose ?? throw new ArgumentNullException(nameof(onDispose)); this.directoryAppend = directoryAppend ?? String.Empty; diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index 30f6a555df5..d31de3c46f4 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -553,7 +553,7 @@ await RunCompileJob( /// The to run and populate. /// The to use. /// The to use. - /// The to use. + /// The to use. /// The to use. /// The to use. /// The for the operation. @@ -563,7 +563,7 @@ async ValueTask RunCompileJob( Models.CompileJob job, Api.Models.Internal.DreamMakerSettings dreamMakerSettings, DreamDaemonLaunchParameters launchParameters, - IByondExecutableLock byondLock, + IEngineExecutableLock byondLock, IRepository repository, IRemoteDeploymentManager remoteDeploymentManager, CancellationToken cancellationToken) @@ -591,7 +591,7 @@ await eventConsumer.HandleEvent( { resolvedOutputDirectory, repoOrigin.ToString(), - $"{byondLock.Version.Major}.{byondLock.Version.Minor}", + byondLock.Version.ToString(), }, true, cancellationToken); @@ -630,14 +630,14 @@ await eventConsumer.HandleEvent( { resolvedOutputDirectory, repoOrigin.ToString(), - $"{byondLock.Version.Major}.{byondLock.Version.Minor}", + byondLock.Version.ToString(), }, true, cancellationToken); // run compiler progressReporter.StageName = "Running DreamMaker"; - var exitCode = await RunDreamMaker(byondLock.DreamMakerPath, job, cancellationToken); + var compileSuceeded = await RunDreamMaker(byondLock, job, cancellationToken); // Session takes ownership of the lock and Disposes it so save this for later var byondVersion = byondLock.Version; @@ -645,10 +645,10 @@ await eventConsumer.HandleEvent( // verify api try { - if (exitCode != 0) + if (!compileSuceeded) throw new JobException( ErrorCode.DreamMakerExitCode, - new JobException($"Exit code: {exitCode}{Environment.NewLine}{Environment.NewLine}{job.Output}")); + new JobException($"Compilation failed:{Environment.NewLine}{Environment.NewLine}{job.Output}")); progressReporter.StageName = "Validating DMAPI"; await VerifyApi( @@ -670,7 +670,7 @@ await eventConsumer.HandleEvent( new List { resolvedOutputDirectory, - exitCode == 0 ? "1" : "0", + compileSuceeded ? "1" : "0", byondVersion.ToString(), }, true, @@ -769,7 +769,7 @@ async ValueTask ProgressTask(JobProgressReporter progressReporter, TimeSpan? est /// The timeout in seconds for validation. /// The level to use to validate the API. /// The for the operation. - /// The current . + /// The current . /// The port to use for API validation. /// If the API validation is required to complete the deployment. /// If output should be logged to the DreamDaemon Diagnostics folder. @@ -779,7 +779,7 @@ async ValueTask VerifyApi( uint timeout, DreamDaemonSecurity securityLevel, Models.CompileJob job, - IByondExecutableLock byondLock, + IEngineExecutableLock byondLock, ushort portToUse, bool requireValidate, bool logOutput, @@ -803,7 +803,11 @@ async ValueTask VerifyApi( job.MinimumSecurityLevel = securityLevel; // needed for the TempDmbProvider ApiValidationStatus validationStatus; - using (var provider = new TemporaryDmbProvider(ioManager.ResolvePath(job.DirectoryName.ToString()), String.Concat(job.DmeName, DmbExtension), job)) + using (var provider = new TemporaryDmbProvider( + ioManager.ResolvePath(job.DirectoryName.ToString()), + String.Concat(job.DmeName, DmbExtension), + job, + byondLock.Version)) await using (var controller = await sessionControllerFactory.LaunchNew(provider, byondLock, launchParameters, true, cancellationToken)) { var launchResult = await controller.LaunchResult.WaitAsync(cancellationToken); @@ -853,33 +857,46 @@ async ValueTask VerifyApi( /// /// Compiles a .dme with DreamMaker. /// - /// The path to the DreamMaker executable. + /// The to use. /// The for the operation. /// The for the operation. - /// A representing the running operation. - async ValueTask RunDreamMaker(string dreamMakerPath, Models.CompileJob job, CancellationToken cancellationToken) + /// A resulting in if compilation succeeded, otherwise. + async ValueTask RunDreamMaker(IEngineExecutableLock engineLock, Models.CompileJob job, CancellationToken cancellationToken) { - await using var dm = processExecutor.LaunchProcess( - dreamMakerPath, - ioManager.ResolvePath( - job.DirectoryName.ToString()), - $"-clean {job.DmeName}.{DmeExtension}", - readStandardHandles: true, - noShellExecute: true); - - if (sessionConfiguration.LowPriorityDeploymentProcesses) - dm.AdjustPriority(false); - - int exitCode; - using (cancellationToken.Register(() => dm.Terminate())) - exitCode = (await dm.Lifetime).Value; - cancellationToken.ThrowIfCancellationRequested(); + var arguments = engineLock.FormatCompilerArguments($"{job.DmeName}.{DmeExtension}"); + bool result; + if (arguments == null) + { + logger.LogTrace("Engine lock says compilation isn't necessary."); + job.Output = $"{engineLock.Version.Engine} does not require compilation."; + result = true; + } + else + { + await using var dm = processExecutor.LaunchProcess( + engineLock.CompilerExePath, + ioManager.ResolvePath( + job.DirectoryName.ToString()), + arguments, + readStandardHandles: true, + noShellExecute: true); + + if (sessionConfiguration.LowPriorityDeploymentProcesses) + dm.AdjustPriority(false); + + int exitCode; + using (cancellationToken.Register(() => dm.Terminate())) + exitCode = (await dm.Lifetime).Value; + cancellationToken.ThrowIfCancellationRequested(); + + logger.LogDebug("DreamMaker exit code: {exitCode}", exitCode); + job.Output = $"{await dm.GetCombinedOutput(cancellationToken)}{Environment.NewLine}{Environment.NewLine}Exit Code: {exitCode}"; + logger.LogDebug("DreamMaker output: {newLine}{output}", Environment.NewLine, job.Output); + result = exitCode == 0; + } - logger.LogDebug("DreamMaker exit code: {exitCode}", exitCode); - job.Output = await dm.GetCombinedOutput(cancellationToken); currentDreamMakerOutput = job.Output; - logger.LogDebug("DreamMaker output: {newLine}{output}", Environment.NewLine, job.Output); - return exitCode; + return result; } /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs index efc773a9193..8f81cb7fbc1 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs @@ -1,6 +1,6 @@ using System; -using Tgstation.Server.Host.Models; +using Tgstation.Server.Api.Models.Internal; namespace Tgstation.Server.Host.Components.Deployment { @@ -22,7 +22,12 @@ public interface IDmbProvider : IDisposable /// /// The of the .dmb. /// - CompileJob CompileJob { get; } + Models.CompileJob CompileJob { get; } + + /// + /// The used to build the .dmb. + /// + ByondVersion ByondVersion { get; } /// /// Disposing the won't cause a cleanup of the working directory. diff --git a/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs index b3d8505e659..cfa69ede089 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs @@ -2,8 +2,8 @@ using System.Threading; using System.Threading.Tasks; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; -using Tgstation.Server.Host.Models; namespace Tgstation.Server.Host.Components.Deployment { @@ -24,7 +24,10 @@ sealed class SwappableDmbProvider : IDmbProvider public string Directory => ioManager.ResolvePath(LiveGameDirectory); /// - public CompileJob CompileJob => baseProvider.CompileJob; + public Models.CompileJob CompileJob => baseProvider.CompileJob; + + /// + public ByondVersion ByondVersion => baseProvider.ByondVersion; /// /// If has been run. diff --git a/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs index 0bf982cfa38..5ecc6b96709 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs @@ -1,6 +1,6 @@ using System; -using Tgstation.Server.Host.Models; +using Tgstation.Server.Api.Models.Internal; namespace Tgstation.Server.Host.Components.Deployment { @@ -16,7 +16,10 @@ sealed class TemporaryDmbProvider : IDmbProvider public string Directory { get; } /// - public CompileJob CompileJob { get; } + public Models.CompileJob CompileJob { get; } + + /// + public ByondVersion ByondVersion { get; } /// /// Initializes a new instance of the class. @@ -24,11 +27,13 @@ sealed class TemporaryDmbProvider : IDmbProvider /// The value of . /// The value of . /// The value of . - public TemporaryDmbProvider(string directory, string dmb, CompileJob compileJob) + /// The value of . + public TemporaryDmbProvider(string directory, string dmb, Models.CompileJob compileJob, ByondVersion byondVersion) { DmbName = dmb ?? throw new ArgumentNullException(nameof(dmb)); Directory = directory ?? throw new ArgumentNullException(nameof(directory)); CompileJob = compileJob ?? throw new ArgumentNullException(nameof(compileJob)); + ByondVersion = byondVersion ?? throw new ArgumentNullException(nameof(byondVersion)); } /// diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs index b5bbf07f902..4ece5faa3e2 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs @@ -16,14 +16,14 @@ interface ISessionControllerFactory /// Create a from a freshly launch DreamDaemon instance. /// /// The to use. - /// The current if any. + /// The current if any. /// The to use. will be updated with the minumum required security level for the launch. /// If the should only validate the DMAPI then exit. /// The for the operation. /// A resulting in a new . ValueTask LaunchNew( IDmbProvider dmbProvider, - IByondExecutableLock currentByondLock, + IEngineExecutableLock currentByondLock, DreamDaemonLaunchParameters launchParameters, bool apiValidate, CancellationToken cancellationToken); diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index d3749f0e9ff..13e6d0705a6 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -123,9 +123,9 @@ async Task Wrap() readonly IProcess process; /// - /// The for the . + /// The for the . /// - readonly IByondExecutableLock byondLock; + readonly IEngineExecutableLock byondLock; /// /// The for the . @@ -244,7 +244,7 @@ public SessionController( ReattachInformation reattachInformation, Api.Models.Instance metadata, IProcess process, - IByondExecutableLock byondLock, + IEngineExecutableLock byondLock, global::Byond.TopicSender.ITopicClient byondTopicSender, IChatTrackingContext chatTrackingContext, IBridgeRegistrar bridgeRegistrar, diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 3bc79939c7d..e45ed439d62 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -6,8 +6,6 @@ using System.Threading; using System.Threading.Tasks; -using Byond.TopicSender; - using Microsoft.Extensions.Logging; using Tgstation.Server.Api.Models; @@ -128,38 +126,6 @@ sealed class SessionControllerFactory : ISessionControllerFactory /// readonly Api.Models.Instance instance; - /// - /// Change a given into the appropriate DreamDaemon command line word. - /// - /// The level to change. - /// A representation of the command line parameter. - static string SecurityWord(DreamDaemonSecurity securityLevel) - { - return securityLevel switch - { - DreamDaemonSecurity.Safe => "safe", - DreamDaemonSecurity.Trusted => "trusted", - DreamDaemonSecurity.Ultrasafe => "ultrasafe", - _ => throw new ArgumentOutOfRangeException(nameof(securityLevel), securityLevel, String.Format(CultureInfo.InvariantCulture, "Bad DreamDaemon security level: {0}", securityLevel)), - }; - } - - /// - /// Change a given into the appropriate DreamDaemon command line word. - /// - /// The level to change. - /// A representation of the command line parameter. - static string VisibilityWord(DreamDaemonVisibility visibility) - { - return visibility switch - { - DreamDaemonVisibility.Public => "public", - DreamDaemonVisibility.Private => "private", - DreamDaemonVisibility.Invisible => "invisible", - _ => throw new ArgumentOutOfRangeException(nameof(visibility), visibility, String.Format(CultureInfo.InvariantCulture, "Bad DreamDaemon visibility level: {0}", visibility)), - }; - } - /// /// Check if a given can be bound to. /// @@ -242,7 +208,7 @@ public SessionControllerFactory( #pragma warning disable CA1506 // TODO: Decomplexify public async ValueTask LaunchNew( IDmbProvider dmbProvider, - IByondExecutableLock currentByondLock, + IEngineExecutableLock currentByondLock, DreamDaemonLaunchParameters launchParameters, bool apiValidate, CancellationToken cancellationToken) @@ -274,7 +240,7 @@ public async ValueTask LaunchNew( // get the byond lock var byondLock = currentByondLock ?? await byond.UseExecutables( - Version.Parse(dmbProvider.CompileJob.ByondVersion), + dmbProvider.ByondVersion, gameIOManager.ConcatPath(dmbProvider.Directory, dmbProvider.DmbName), cancellationToken); try @@ -289,7 +255,7 @@ public async ValueTask LaunchNew( string outputFilePath = null; var preserveLogFile = true; - var cliSupported = byondLock.SupportsCli; + var hasStandardOutput = byondLock.HasStandardOutput; if (launchParameters.LogOutput.Value) { var now = DateTimeOffset.UtcNow; @@ -302,7 +268,7 @@ public async ValueTask LaunchNew( logger.LogInformation("Logging DreamDaemon output to {path}...", outputFilePath); } - else if (!cliSupported) + else if (!hasStandardOutput) { outputFilePath = gameIOManager.ConcatPath(dmbProvider.Directory, $"{Guid.NewGuid()}.dd.log"); preserveLogFile = false; @@ -310,17 +276,12 @@ public async ValueTask LaunchNew( var accessIdentifier = cryptographySuite.GetSecureString(); - var byondTopicSender = topicClientFactory.CreateTopicClient( - TimeSpan.FromMilliseconds( - launchParameters.TopicRequestTimeout.Value)); - if (!apiValidate && dmbProvider.CompileJob.DMApiVersion == null) logger.LogDebug("Session will have no DMAPI support!"); // launch dd - var process = await CreateDreamDaemonProcess( + var process = await CreateGameServerProcess( dmbProvider, - byondTopicSender, byondLock, launchParameters, accessIdentifier, @@ -347,6 +308,10 @@ public async ValueTask LaunchNew( accessIdentifier, launchParameters.Port.Value); + var byondTopicSender = topicClientFactory.CreateTopicClient( + TimeSpan.FromMilliseconds( + launchParameters.TopicRequestTimeout.Value)); + var sessionController = new SessionController( reattachInformation, instance, @@ -362,7 +327,7 @@ public async ValueTask LaunchNew( () => LogDDOutput( process, outputFilePath, - cliSupported, + hasStandardOutput, preserveLogFile, CancellationToken.None), // DCT: None available launchParameters.StartupTimeout, @@ -406,7 +371,7 @@ public async ValueTask Reattach( logger.LogTrace("Begin session reattach..."); var byondTopicSender = topicClientFactory.CreateTopicClient(reattachInformation.TopicRequestTimeout); var byondLock = await byond.UseExecutables( - Version.Parse(reattachInformation.Dmb.CompileJob.ByondVersion), + reattachInformation.Dmb.ByondVersion, null, // Doesn't matter if it's trusted or not on reattach cancellationToken); @@ -423,7 +388,7 @@ public async ValueTask Reattach( try { - if (!byondLock.SupportsCli) + if (byondLock.PromptsForNetworkAccess) networkPromptReaper.RegisterProcess(process); var chatTrackingContext = chat.CreateTrackingContext(); @@ -479,60 +444,45 @@ public async ValueTask Reattach( } /// - /// Creates the DreamDaemon . + /// Creates the game server . /// /// The . - /// The to use for sanitization. - /// The . + /// The . /// The . /// The secure string to use for the session. /// The path to log DreamDaemon output to. /// If we are only validating the DMAPI then exiting. /// The for the operation. /// A resulting in the DreamDaemon . - async ValueTask CreateDreamDaemonProcess( + async ValueTask CreateGameServerProcess( IDmbProvider dmbProvider, - ITopicClient byondTopicSender, - IByondExecutableLock byondLock, + IEngineExecutableLock byondLock, DreamDaemonLaunchParameters launchParameters, string accessIdentifier, string logFilePath, bool apiValidate, CancellationToken cancellationToken) { - // set command line options - // more sanitization here cause it uses the same scheme - var parameters = $"{DMApiConstants.ParamApiVersion}={byondTopicSender.SanitizeString(DMApiConstants.InteropVersion.Semver().ToString())}&{byondTopicSender.SanitizeString(DMApiConstants.ParamServerPort)}={serverPortProvider.HttpApiPort}&{byondTopicSender.SanitizeString(DMApiConstants.ParamAccessIdentifier)}={byondTopicSender.SanitizeString(accessIdentifier)}"; - - if (!String.IsNullOrEmpty(launchParameters.AdditionalParameters)) - parameters = $"{parameters}&{launchParameters.AdditionalParameters}"; - // important to run on all ports to allow port changing - var arguments = String.Format( - CultureInfo.InvariantCulture, - "{0} -port {1} -ports 1-65535 {2}-close -verbose -{3} -{4}{5}{6}{7} -params \"{8}\"", - dmbProvider.DmbName, - launchParameters.Port.Value, - launchParameters.AllowWebClient.Value ? "-webclient " : String.Empty, - SecurityWord(launchParameters.SecurityLevel.Value), - VisibilityWord(launchParameters.Visibility.Value), - !byondLock.SupportsCli - ? $" -logself -log {logFilePath}" - : String.Empty, // DD doesn't output anything if -logself is set??? - launchParameters.StartProfiler.Value - ? " -profile" - : String.Empty, - byondLock.SupportsMapThreads && launchParameters.MapThreads.Value != 0 - ? $" -map-threads {launchParameters.MapThreads.Value}" - : String.Empty, - parameters); + var arguments = byondLock.FormatServerArguments( + dmbProvider, + new Dictionary + { + { DMApiConstants.ParamApiVersion, DMApiConstants.InteropVersion.Semver().ToString() }, + { DMApiConstants.ParamServerPort, serverPortProvider.HttpApiPort.ToString(CultureInfo.InvariantCulture) }, + { DMApiConstants.ParamAccessIdentifier, accessIdentifier }, + }, + launchParameters, + !byondLock.HasStandardOutput + ? logFilePath + : null); var process = processExecutor.LaunchProcess( - byondLock.DreamDaemonPath, + byondLock.ServerExePath, dmbProvider.Directory, arguments, logFilePath, - byondLock.SupportsCli, + byondLock.HasStandardOutput, true); try @@ -545,7 +495,7 @@ async ValueTask CreateDreamDaemonProcess( else if (sessionConfiguration.LowPriorityDeploymentProcesses) process.AdjustPriority(false); - if (!byondLock.SupportsCli) + if (!byondLock.HasStandardOutput) networkPromptReaper.RegisterProcess(process); // If this isnt a staging DD (From a Deployment), fire off an event diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index 156ff784e93..19212d7c5b0 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -43,7 +43,7 @@ public sealed class ByondController : InstanceRequiredController /// /// The to normalize. /// The normalized . May be a reference to . - static Version NormalizeVersion(Version version) => version.Build == 0 ? new Version(version.Major, version.Minor) : version; + static Version NormalizeByondVersion(Version version) => version.Build == 0 ? new Version(version.Major, version.Minor) : version; /// /// Initializes a new instance of the class. @@ -72,23 +72,26 @@ public ByondController( } /// - /// Gets the active . + /// Gets the active . /// /// A resulting in the for the operation. /// Retrieved version information successfully. + /// No BYOND versions installed. [HttpGet] [TgsAuthorize(ByondRights.ReadActive)] [ProducesResponseType(typeof(ByondResponse), 200)] + [ProducesResponseType(typeof(ErrorMessageResponse), 409)] public ValueTask Read() => WithComponentInstance(instance => ValueTask.FromResult( - Json(new ByondResponse - { - Version = instance.ByondManager.ActiveVersion, - }))); + instance.ByondManager.ActiveVersion != null + ? Json( + new ByondResponse( + instance.ByondManager.ActiveVersion)) + : Conflict(new ErrorMessageResponse(ErrorCode.ResourceNotPresent)))); /// - /// Lists installed s. + /// Lists installed s. /// /// The current page. /// The page size. @@ -106,10 +109,7 @@ public ValueTask List([FromQuery] int? page, [FromQuery] int? pag instance .ByondManager .InstalledVersions - .Select(x => new ByondResponse - { - Version = x, - }) + .Select(x => new ByondResponse(x)) .AsQueryable() .OrderBy(x => x.Version))), null, @@ -126,27 +126,42 @@ public ValueTask List([FromQuery] int? page, [FromQuery] int? pag /// Switched active version successfully. /// Created to install and switch active version successfully. [HttpPost] - [TgsAuthorize(ByondRights.InstallOfficialOrChangeActiveVersion | ByondRights.InstallCustomVersion)] + [TgsAuthorize( + ByondRights.InstallOfficialOrChangeActiveByondVersion + | ByondRights.InstallCustomByondVersion + | ByondRights.InstallOfficialOrChangeActiveOpenDreamVersion + | ByondRights.InstallCustomOpenDreamVersion)] [ProducesResponseType(typeof(ByondInstallResponse), 200)] [ProducesResponseType(typeof(ByondInstallResponse), 202)] -#pragma warning disable CA1506 // TODO: Decomplexify +#pragma warning disable CA1502 // TODO: Decomplexify +#pragma warning disable CA1506 public async ValueTask Update([FromBody] ByondVersionRequest model, CancellationToken cancellationToken) #pragma warning restore CA1506 +#pragma warning restore CA1502 { ArgumentNullException.ThrowIfNull(model); var uploadingZip = model.UploadCustomZip == true; + var isByondEngine = model.Engine.Value == EngineType.Byond; - if (model.Version == null - || model.Version.Revision != -1 - || (uploadingZip && model.Version.Build > 0)) + if ((isByondEngine && (model.Version.Revision != -1 || (uploadingZip && model.Version.Build > 0) || model.SourceCommittish != null || model.SourceRepository != null)) + || (!isByondEngine && (model.Version != null || String.IsNullOrWhiteSpace(model.SourceCommittish)))) return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); - var version = NormalizeVersion(model.Version); + Uri sourceRepo; + if (isByondEngine) + { + model.Version = NormalizeByondVersion(model.Version); + sourceRepo = null; + } + else + { + sourceRepo = model.SourceRepository ?? new Uri("https://github.com/OpenDreamProject/OpenDream"); + } var userByondRights = AuthenticationContext.InstancePermissionSet.ByondRights.Value; - if ((!userByondRights.HasFlag(ByondRights.InstallOfficialOrChangeActiveVersion) && !uploadingZip) - || (!userByondRights.HasFlag(ByondRights.InstallCustomVersion) && uploadingZip)) + if ((!userByondRights.HasFlag(ByondRights.InstallOfficialOrChangeActiveByondVersion) && !uploadingZip) + || (!userByondRights.HasFlag(ByondRights.InstallCustomByondVersion) && uploadingZip)) return Forbid(); // remove cruff fields @@ -155,44 +170,50 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode async instance => { var byondManager = instance.ByondManager; - var versionAlreadyInstalled = !uploadingZip && byondManager.InstalledVersions.Any(x => x == version); + var versionAlreadyInstalled = !uploadingZip && byondManager.InstalledVersions.Any(x => x.Equals(model)); if (versionAlreadyInstalled) { Logger.LogInformation( - "User ID {userId} changing instance ID {instanceId} BYOND version to {newByondVersion}", + "User ID {userId} changing instance ID {instanceId} {engineType} version to {newByondVersion}", AuthenticationContext.User.Id, Instance.Id, - version); + model.Engine, + model.Version); try { - await byondManager.ChangeVersion(null, version, null, false, cancellationToken); + await byondManager.ChangeVersion(null, model, null, false, cancellationToken); } catch (InvalidOperationException ex) { Logger.LogDebug( ex, - "Race condition: BYOND version {version} uninstalled before we could switch to it. Creating install job instead...", - version); + "Race condition: {engineType} version {version} uninstalled before we could switch to it. Creating install job instead...", + model.Engine.Value, + model.Version); versionAlreadyInstalled = false; } } if (!versionAlreadyInstalled) { - if (version.Build > 0) + if (model.Version.Build > 0) return BadRequest(new ErrorMessageResponse(ErrorCode.ByondNonExistentCustomVersion)); Logger.LogInformation( - "User ID {userId} installing BYOND version to {newByondVersion} on instance ID {instanceId}", + "User ID {userId} installing {engineType} version {newByondVersion}{sourceCommittish} on instance ID {instanceId}", AuthenticationContext.User.Id, - version, + model.Engine.Value, + model.Version, + model.SourceCommittish != null + ? $" ({model.SourceCommittish})" + : String.Empty, Instance.Id); // run the install through the job manager var job = new Job { - Description = $"Install {(!uploadingZip ? String.Empty : "custom ")}BYOND version {version}", + Description = $"Install {(!uploadingZip ? String.Empty : "custom ")}{model.Engine.Value} version {model.Version}", StartedBy = AuthenticationContext.User, CancelRightsType = RightsType.Byond, CancelRight = (ulong)ByondRights.CancelInstall, @@ -209,7 +230,13 @@ await jobManager.RegisterOperation( job, async (core, databaseContextFactory, paramJob, progressHandler, jobCancellationToken) => { - Stream zipFileStream = null; + if (sourceRepo != null) + await core.ByondManager.EnsureEngineSource( + sourceRepo, + model.Engine.Value, + jobCancellationToken); + + MemoryStream zipFileStream = null; if (fileUploadTicket != null) await using (fileUploadTicket) { @@ -229,7 +256,7 @@ await jobManager.RegisterOperation( await using (zipFileStream) await core.ByondManager.ChangeVersion( progressHandler, - version, + model, zipFileStream, true, jobCancellationToken); @@ -260,7 +287,7 @@ await core.ByondManager.ChangeVersion( /// A resulting in the for the operation. /// Created to delete target version successfully. /// Attempted to delete the active BYOND . - /// The specified was not installed. + /// The specified was not installed. [HttpDelete] [TgsAuthorize(ByondRights.DeleteInstall)] [ProducesResponseType(typeof(JobResponse), 202)] @@ -270,22 +297,22 @@ public async ValueTask Delete([FromBody] ByondVersionDeleteReques { ArgumentNullException.ThrowIfNull(model); - if (model.Version == null - || model.Version.Revision != -1) + if (model.Version.Revision != -1) return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); - var version = NormalizeVersion(model.Version); + if (model.Engine == EngineType.Byond) + model.Version = NormalizeByondVersion(model.Version); var notInstalledResponse = await WithComponentInstance( instance => { var byondManager = instance.ByondManager; - if (version == byondManager.ActiveVersion) + if (model.Equals(byondManager.ActiveVersion)) return ValueTask.FromResult( Conflict(new ErrorMessageResponse(ErrorCode.ByondCannotDeleteActiveVersion))); - var versionNotInstalled = !byondManager.InstalledVersions.Any(x => x == version); + var versionNotInstalled = !byondManager.InstalledVersions.Any(x => x.Equals(model)); return ValueTask.FromResult( versionNotInstalled @@ -296,22 +323,27 @@ public async ValueTask Delete([FromBody] ByondVersionDeleteReques if (notInstalledResponse != null) return notInstalledResponse; - var isCustomVersion = version.Build != -1; + var isByondVersion = model.Engine.Value == EngineType.Byond; // run the install through the job manager var job = new Job { - Description = $"Delete installed BYOND version {version}", + Description = $"Delete installed {model.Engine.Value} version {model.Version}", StartedBy = AuthenticationContext.User, CancelRightsType = RightsType.Byond, - CancelRight = (ulong)(isCustomVersion ? ByondRights.InstallOfficialOrChangeActiveVersion : ByondRights.InstallCustomVersion), + CancelRight = (ulong)( + isByondVersion + ? model.Version.Build != -1 + ? ByondRights.InstallOfficialOrChangeActiveByondVersion + : ByondRights.InstallCustomByondVersion + : ByondRights.InstallCustomOpenDreamVersion | ByondRights.InstallOfficialOrChangeActiveOpenDreamVersion), Instance = Instance, }; await jobManager.RegisterOperation( job, (instanceCore, databaseContextFactory, job, progressReporter, jobCancellationToken) - => instanceCore.ByondManager.DeleteVersion(progressReporter, version, jobCancellationToken), + => instanceCore.ByondManager.DeleteVersion(progressReporter, model, jobCancellationToken), cancellationToken); var apiResponse = job.ToApi(); diff --git a/src/Tgstation.Server.Host/Models/CompileJob.cs b/src/Tgstation.Server.Host/Models/CompileJob.cs index 9ddde1344c1..a5f5ac67d04 100644 --- a/src/Tgstation.Server.Host/Models/CompileJob.cs +++ b/src/Tgstation.Server.Host/Models/CompileJob.cs @@ -82,7 +82,7 @@ public override Version DMApiVersion } /// - public CompileJobResponse ToApi() => new CompileJobResponse + public CompileJobResponse ToApi() => new () { DirectoryName = DirectoryName, DmeName = DmeName, @@ -90,7 +90,9 @@ public override Version DMApiVersion Job = Job.ToApi(), Output = Output, RevisionInformation = RevisionInformation.ToApi(), - ByondVersion = Version.Parse(ByondVersion), + ByondVersion = Api.Models.Internal.ByondVersion.TryParse(ByondVersion, out var version) + ? version + : throw new InvalidOperationException($"Failed to parse BYOND version: {ByondVersion}"), MinimumSecurityLevel = MinimumSecurityLevel, DMApiVersion = DMApiVersion, RepositoryOrigin = RepositoryOrigin != null ? new Uri(RepositoryOrigin) : null, diff --git a/tests/Tgstation.Server.Api.Tests/Rights/TestRights.cs b/tests/Tgstation.Server.Api.Tests/Rights/TestRights.cs index 62e41b7d982..e773f4da941 100644 --- a/tests/Tgstation.Server.Api.Tests/Rights/TestRights.cs +++ b/tests/Tgstation.Server.Api.Tests/Rights/TestRights.cs @@ -40,7 +40,7 @@ public void TestAllPowerOfTwo() [TestMethod] public void TestAllRightsWorks() { - var allByondRights = ByondRights.CancelInstall | ByondRights.InstallOfficialOrChangeActiveVersion | ByondRights.ListInstalled | ByondRights.ReadActive | ByondRights.InstallCustomVersion | ByondRights.DeleteInstall; + var allByondRights = ByondRights.CancelInstall | ByondRights.InstallOfficialOrChangeActiveByondVersion | ByondRights.ListInstalled | ByondRights.ReadActive | ByondRights.InstallCustomByondVersion | ByondRights.DeleteInstall; var automaticByondRights = RightsHelper.AllRights(); Assert.AreEqual(allByondRights, automaticByondRights); diff --git a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs index d4c81db6c3b..3027f9ac45a 100644 --- a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs +++ b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs @@ -11,6 +11,8 @@ using System.Threading.Tasks; using Tgstation.Server.Api; +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Common.Http; @@ -22,10 +24,12 @@ public sealed class TestApiClient [TestMethod] public async Task TestDeserializingByondModelsWork() { - var sample = new ByondResponse - { - Version = new Version(511, 1385, 0) - }; + var sample = new ByondResponse( + new ByondVersion + { + Engine = EngineType.Byond, + Version = new Version(511, 1385, 0) + }); var sampleJson = JsonConvert.SerializeObject(sample, new JsonSerializerSettings { @@ -51,10 +55,12 @@ public async Task TestDeserializingByondModelsWork() [TestMethod] public async Task TestUnrecognizedResponse() { - var sample = new ByondResponse - { - Version = new Version(511, 1385) - }; + var sample = new ByondResponse( + new ByondVersion + { + Engine = EngineType.Byond, + Version = new Version(511, 1385) + }); var fakeJson = "asdfasd <>F#(*)U*#JLI"; diff --git a/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs index dccf90d3e07..c57e72afa16 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs @@ -6,6 +6,8 @@ using System.Linq; using System.Threading.Tasks; +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; namespace Tgstation.Server.Host.Components.Byond.Tests @@ -62,7 +64,11 @@ public async Task TestDownload() new MemoryStream(ourArray))) .Verifiable(); - var result = await installer.DownloadVersion(new Version(511, 1385), default); + var result = await installer.DownloadVersion(new ByondVersion + { + Engine = EngineType.Byond, + Version = new Version(123, 252345), + }, default); Assert.IsTrue(ourArray.SequenceEqual(result.ToArray())); mockIOManager.Verify(); @@ -79,9 +85,17 @@ public async Task TestInstallByond() const string FakePath = "fake"; await Assert.ThrowsExceptionAsync(() => installer.InstallByond(null, null, default).AsTask()); - await Assert.ThrowsExceptionAsync(() => installer.InstallByond(new Version(123,252345), null, default).AsTask()); - await installer.InstallByond(new Version(511, 1385), FakePath, default); + var byondVersion = new ByondVersion + { + Engine = EngineType.Byond, + Version = new Version(123, 252345), + }; + + await Assert.ThrowsExceptionAsync(() => installer.InstallByond(byondVersion, null, default).AsTask()); + + byondVersion.Version = new Version(511, 1385); + await installer.InstallByond(byondVersion, FakePath, default); mockPostWriteHandler.Verify(x => x.HandleWrite(It.IsAny()), Times.Exactly(4)); } diff --git a/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs b/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs index 090f10f1ec3..fb0bea813d0 100644 --- a/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs +++ b/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs @@ -1,4 +1,4 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using System; @@ -50,7 +50,7 @@ public void TestGetRightsGeneric() var authContext = new AuthenticationContext(null, user, instanceUser); user.PermissionSet.AdministrationRights = AdministrationRights.WriteUsers; - instanceUser.ByondRights = ByondRights.InstallOfficialOrChangeActiveVersion | ByondRights.ReadActive; + instanceUser.ByondRights = ByondRights.InstallOfficialOrChangeActiveByondVersion | ByondRights.ReadActive; Assert.AreEqual((ulong)user.PermissionSet.AdministrationRights, authContext.GetRight(RightsType.Administration)); Assert.AreEqual((ulong)instanceUser.ByondRights, authContext.GetRight(RightsType.Byond)); } diff --git a/tests/Tgstation.Server.Tests/CachingFileDownloader.cs b/tests/Tgstation.Server.Tests/CachingFileDownloader.cs index 17dcbbfaf59..e00206bfe0f 100644 --- a/tests/Tgstation.Server.Tests/CachingFileDownloader.cs +++ b/tests/Tgstation.Server.Tests/CachingFileDownloader.cs @@ -9,6 +9,7 @@ using Moq; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; @@ -42,9 +43,9 @@ public static async Task InitializeAndInjectForLiveTests(CancellationToken cance var logger = loggerFactory.CreateLogger("CachingFileDownloader"); var cfd = new CachingFileDownloader(loggerFactory.CreateLogger()); - var edgeVersion = await ByondTest.GetEdgeVersion(cfd, cancellationToken); + var edgeVersion = await ByondTest.GetEdgeVersion(Api.Models.EngineType.Byond, cfd, cancellationToken); - await InitializeByondVersion(logger, edgeVersion, new PlatformIdentifier().IsWindows, cancellationToken); + await InitializeByondVersion(logger, edgeVersion.Version, new PlatformIdentifier().IsWindows, cancellationToken); // predownload the target github release update asset var gitHubToken = Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"); @@ -76,10 +77,16 @@ public static async Task InitializeAndInjectForLiveTests(CancellationToken cance ServiceCollectionExtensions.UseFileDownloader(); } - public static async ValueTask InitializeByondVersion(ILogger logger, Version version, bool windows, CancellationToken cancellationToken) + public static async ValueTask InitializeByondVersion(ILogger logger, Version byondVersion, bool windows, CancellationToken cancellationToken) { + var version = new ByondVersion + { + Engine = Api.Models.EngineType.Byond, + Version = byondVersion, + }; + var url = new Uri( - $"https://www.byond.com/download/build/{version.Major}/{version.Major}.{version.Minor}_byond{(!windows ? "_linux" : string.Empty)}.zip"); + $"https://www.byond.com/download/build/{version.Version.Major}/{version.Version.Major}.{version.Version.Minor}_byond{(!windows ? "_linux" : string.Empty)}.zip"); string path = null; if (TestingUtils.RunningInGitHubActions) { @@ -91,7 +98,7 @@ public static async ValueTask InitializeByondVersion(ILogger logger, Version ver windows ? "windows" : "linux"); path = Path.Combine( dir, - $"{version.Major}.{version.Minor}.zip"); + $"{version.Version.Major}.{version.Version.Minor}.zip"); } await (await CacheFile(logger, url, null, path, cancellationToken)).DisposeAsync(); diff --git a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs index 4f1ddf73873..255e162c8d9 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs @@ -12,6 +12,7 @@ using Newtonsoft.Json; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Chat.Commands; using Tgstation.Server.Host.Components.Chat.Providers; @@ -100,7 +101,15 @@ public override ValueTask SendMessage(Message replyTo, MessageContent message, u return ValueTask.CompletedTask; } - public override ValueTask>>> SendUpdateMessage(RevisionInformation revisionInformation, Version byondVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, ulong channelId, bool localCommitPushed, CancellationToken cancellationToken) + public override ValueTask>>> SendUpdateMessage( + Host.Models.RevisionInformation revisionInformation, + ByondVersion byondVersion, + DateTimeOffset? estimatedCompletionTime, + string gitHubOwner, + string gitHubRepo, + ulong channelId, + bool localCommitPushed, + CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(revisionInformation); ArgumentNullException.ThrowIfNull(byondVersion); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index eedac0cd0e5..3e9f5ca84c9 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -6,13 +6,17 @@ using System.Threading; using System.Threading.Tasks; +using Elasticsearch.Net.Specification.IndexLifecycleManagementApi; + using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client; @@ -32,16 +36,22 @@ sealed class ByondTest : JobsRequiredTest readonly Api.Models.Instance metadata; - static Version edgeVersion; + static Dictionary edgeVersions = new Dictionary + { + { EngineType.Byond, null }, + { EngineType.OpenDream, null } + }; - Version testVersion; + ByondVersion testVersion; + EngineType testEngine; - public ByondTest(IByondClient byondClient, IJobsClient jobsClient, IFileDownloader fileDownloader, Api.Models.Instance metadata) + public ByondTest(IByondClient byondClient, IJobsClient jobsClient, IFileDownloader fileDownloader, Api.Models.Instance metadata, EngineType engineType) : base(jobsClient) { this.byondClient = byondClient ?? throw new ArgumentNullException(nameof(byondClient)); this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); + this.testEngine = engineType; } public Task Run(CancellationToken cancellationToken, out Task firstInstall) @@ -50,42 +60,67 @@ public Task Run(CancellationToken cancellationToken, out Task firstInstall) return RunContinued(firstInstall, cancellationToken); } - public static async Task GetEdgeVersion(IFileDownloader fileDownloader, CancellationToken cancellationToken) + public static async ValueTask GetEdgeVersion(EngineType engineType, IFileDownloader fileDownloader, CancellationToken cancellationToken) { + var edgeVersion = edgeVersions[engineType]; + if (edgeVersion != null) return edgeVersion; - await using var provider = fileDownloader.DownloadFile(new Uri("https://www.byond.com/download/version.txt"), null); - var stream = await provider.GetResult(cancellationToken); - using var reader = new StreamReader(stream, Encoding.UTF8, false, -1, true); - var text = await reader.ReadToEndAsync(); - var splits = text.Split('\n', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); - - var targetVersion = splits.Last(); - - var missingVersionMap = new PlatformIdentifier().IsWindows - ? new Dictionary() - { - } - // linux map also needs updating in CI - : new Dictionary() - { + ByondVersion byondVersion; + if (engineType == EngineType.Byond) + { + await using var provider = fileDownloader.DownloadFile(new Uri("https://www.byond.com/download/version.txt"), null); + var stream = await provider.GetResult(cancellationToken); + using var reader = new StreamReader(stream, Encoding.UTF8, false, -1, true); + var text = await reader.ReadToEndAsync(cancellationToken); + var splits = text.Split('\n', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); + + var targetVersion = splits.Last(); + + var missingVersionMap = new PlatformIdentifier().IsWindows + ? new Dictionary() + { + } + // linux map also needs updating in CI + : new Dictionary() + { { "515.1612", "515.1611" } - }; + }; - if (missingVersionMap.TryGetValue(targetVersion, out var remappedVersion)) - targetVersion = remappedVersion; + if (missingVersionMap.TryGetValue(targetVersion, out var remappedVersion)) + targetVersion = remappedVersion; - return edgeVersion = Version.Parse(targetVersion); + Assert.IsTrue(ByondVersion.TryParse(targetVersion, out byondVersion), $"Bad version: {targetVersion}"); + } + else + { + Assert.Fail($"Edge version retrieval for {engineType} not implemented!"); + return null; + } + + return edgeVersions[engineType] = byondVersion; } async Task RunPartOne(CancellationToken cancellationToken) { - testVersion = await GetEdgeVersion(fileDownloader, cancellationToken); + testVersion = await GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); await TestNoVersion(cancellationToken); + await TestInstallNullVersion(cancellationToken); await TestInstallStable(cancellationToken); } + ValueTask TestInstallNullVersion(CancellationToken cancellationToken) + => ApiAssert.ThrowsException( + () => byondClient.SetActiveVersion( + new ByondVersionRequest + { + Engine = testEngine, + }, + null, + cancellationToken), + ErrorCode.ModelValidationFailure); + async Task RunContinued(Task firstInstall, CancellationToken cancellationToken) { await firstInstall; @@ -98,7 +133,8 @@ async Task TestDeletes(CancellationToken cancellationToken) { var deleteThisOneBecauseItWasntPartOfTheOriginalTest = await byondClient.DeleteVersion(new ByondVersionDeleteRequest { - Version = new(testVersion.Major, testVersion.Minor, 2) + Engine = testEngine, + Version = new(testVersion.Version.Major, testVersion.Version.Minor, 2) }, cancellationToken); await WaitForJob(deleteThisOneBecauseItWasntPartOfTheOriginalTest, 30, false, null, cancellationToken); @@ -112,14 +148,18 @@ async Task TestDeletes(CancellationToken cancellationToken) var uninstallResponseTask = byondClient.DeleteVersion( new ByondVersionDeleteRequest { - Version = testVersion + Version = testVersion.Version, + Engine = testVersion.Engine, + SourceCommittish = testVersion.SourceCommittish, }, cancellationToken); var badBecauseActiveResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( new ByondVersionDeleteRequest { - Version = new(testVersion.Major, testVersion.Minor, 1) + Version = new(testVersion.Version.Major, testVersion.Version.Minor, 1), + Engine = testVersion.Engine, + SourceCommittish = testVersion.SourceCommittish, }, cancellationToken), ErrorCode.ByondCannotDeleteActiveVersion); @@ -140,7 +180,7 @@ async Task TestDeletes(CancellationToken cancellationToken) var newVersions = await byondClient.InstalledVersions(null, cancellationToken); Assert.IsNotNull(newVersions); Assert.AreEqual(1, newVersions.Count); - Assert.AreEqual(new Version(testVersion.Major, testVersion.Minor, 1), newVersions[0].Version); + Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 1), newVersions[0].Version); } async Task TestInstallFakeVersion(CancellationToken cancellationToken) @@ -158,7 +198,9 @@ async Task TestInstallStable(CancellationToken cancellationToken) { var newModel = new ByondVersionRequest { - Version = testVersion + Version = testVersion.Version, + Engine = testVersion.Engine, + SourceCommittish = testVersion.SourceCommittish, }; var test = await byondClient.SetActiveVersion(newModel, null, cancellationToken); Assert.IsNotNull(test.InstallJob); @@ -220,7 +262,9 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) var test = await byondClient.SetActiveVersion( new ByondVersionRequest { - Version = testVersion, + Engine = testVersion.Engine, + Version = testVersion.Version, + SourceCommittish = testVersion.SourceCommittish, UploadCustomZip = true }, stableBytesMs, @@ -234,7 +278,9 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) var test2 = await byondClient.SetActiveVersion( new ByondVersionRequest { - Version = testVersion, + Version = testVersion.Version, + SourceCommittish = testVersion.SourceCommittish, + Engine = testVersion.Engine, UploadCustomZip = true }, stableBytesMs, @@ -244,22 +290,24 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) await WaitForJob(test2.InstallJob, 30, false, null, cancellationToken); var newSettings = await byondClient.ActiveVersion(cancellationToken); - Assert.AreEqual(new Version(testVersion.Major, testVersion.Minor, 2), newSettings.Version); + Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 2), newSettings.Version); // test a few switches var installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest { - Version = testVersion + Version = testVersion.Version, + SourceCommittish = testVersion.SourceCommittish, + Engine = testVersion.Engine, }, null, cancellationToken); Assert.IsNull(installResponse.InstallJob); await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(new ByondVersionRequest { - Version = new Version(testVersion.Major, testVersion.Minor, 3) + Version = new Version(testVersion.Version.Major, testVersion.Version.Minor, 3) }, null, cancellationToken), ErrorCode.ByondNonExistentCustomVersion); installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest { - Version = new Version(testVersion.Major, testVersion.Minor, 1) + Version = new Version(testVersion.Version.Major, testVersion.Version.Minor, 1) }, null, cancellationToken); Assert.IsNull(installResponse.InstallJob); } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index ed0edee01e3..ea17e68033d 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -10,6 +10,7 @@ using Moq; using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client; @@ -43,9 +44,10 @@ public async Task RunTests( ushort ddPort, bool highPrioDD, bool lowPrioDeployment, + EngineType engineType, CancellationToken cancellationToken) { - var byondTest = new ByondTest(instanceClient.Byond, instanceClient.Jobs, fileDownloader, instanceClient.Metadata); + var byondTest = new ByondTest(instanceClient.Byond, instanceClient.Jobs, fileDownloader, instanceClient.Metadata, engineType); var chatTest = new ChatTest(instanceClient.ChatBots, instanceManagerClient, instanceClient.Jobs, instanceClient.Metadata); var configTest = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata); var repoTest = new RepositoryTest(instanceClient.Repository, instanceClient.Jobs); @@ -66,17 +68,23 @@ public async Task RunTests( await byondTask; await new WatchdogTest( - await ByondTest.GetEdgeVersion(fileDownloader, cancellationToken), instanceClient, instanceManager, serverPort, highPrioDD, ddPort).Run(cancellationToken); + await ByondTest.GetEdgeVersion(engineType, fileDownloader, cancellationToken), instanceClient, instanceManager, serverPort, highPrioDD, ddPort).Run(cancellationToken); } public async Task RunCompatTests( - Version compatVersion, + Version compatByondVersion, IInstanceClient instanceClient, ushort dmPort, ushort ddPort, bool highPrioDD, CancellationToken cancellationToken) { + var compatVersion = new ByondVersion + { + Engine = EngineType.Byond, + Version = compatByondVersion, + }; + System.Console.WriteLine($"COMPAT TEST START: {compatVersion}"); const string Origin = "https://github.com/Cyberboss/common_core"; var cloneRequest = instanceClient.Repository.Clone(new RepositoryCreateRequest @@ -155,7 +163,9 @@ public async Task RunCompatTests( installJob2 = await instanceClient.Byond.SetActiveVersion(new ByondVersionRequest { UploadCustomZip = true, - Version = compatVersion, + Version = compatVersion.Version, + Engine = compatVersion.Engine, + SourceCommittish = compatVersion.SourceCommittish }, stableBytesMs, cancellationToken); } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 3c4b9cf460d..2726b4a5761 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -18,6 +18,7 @@ using System.Threading.Tasks; using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client; @@ -57,11 +58,11 @@ sealed class WatchdogTest : JobsRequiredTest readonly ushort ddPort; readonly bool highPrioDD; readonly TopicClient topicClient; - readonly Version testVersion; + readonly ByondVersion testVersion; bool ranTimeoutTest = false; - public WatchdogTest(Version testVersion, IInstanceClient instanceClient, InstanceManager instanceManager, ushort serverPort, bool highPrioDD, ushort ddPort) + public WatchdogTest(ByondVersion testVersion, IInstanceClient instanceClient, InstanceManager instanceManager, ushort serverPort, bool highPrioDD, ushort ddPort) : base(instanceClient.Jobs) { this.instanceClient = instanceClient ?? throw new ArgumentNullException(nameof(instanceClient)); @@ -94,8 +95,9 @@ async Task CheckByondVersions() var byondVersion = list[0]; Assert.AreEqual(1, byondVersion.Version.Build); - Assert.AreEqual(testVersion.Major, byondVersion.Version.Major); - Assert.AreEqual(testVersion.Minor, byondVersion.Version.Minor); + Assert.AreEqual(testVersion.Version.Major, byondVersion.Version.Major); + Assert.AreEqual(testVersion.Version.Minor, byondVersion.Version.Minor); + Assert.AreEqual(testVersion.Engine, byondVersion.Engine); } await Task.WhenAll( @@ -230,10 +232,10 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationToken cancellationToken) { - var testCustomVersion = new Version(testVersion.Major, testVersion.Minor, 1); + var testCustomVersion = new Version(testVersion.Version.Major, testVersion.Version.Minor, 1); var currentByond = await instanceClient.Byond.ActiveVersion(cancellationToken); Assert.IsNotNull(currentByond); - Assert.AreEqual(testVersion.Semver(), currentByond.Version); + Assert.AreEqual(testVersion.Version.Semver(), currentByond.Version); // Change the active version and check we get delayed while deleting the old one because the watchdog is using it var setActiveResponse = await instanceClient.Byond.SetActiveVersion( @@ -250,7 +252,8 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo var deleteJob = await instanceClient.Byond.DeleteVersion( new ByondVersionDeleteRequest { - Version = testVersion, + Version = testVersion.Version, + SourceCommittish = testVersion.SourceCommittish, }, cancellationToken); @@ -265,7 +268,9 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo setActiveResponse = await instanceClient.Byond.SetActiveVersion( new ByondVersionRequest { - Version = testVersion, + Version = testVersion.Version, + Engine = testVersion.Engine, + SourceCommittish = testVersion.SourceCommittish }, null, cancellationToken); @@ -291,7 +296,9 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo deleteJob = await instanceClient.Byond.DeleteVersion( new ByondVersionDeleteRequest { - Version = testVersion, + Version = testVersion.Version, + Engine = testVersion.Engine, + SourceCommittish = testVersion.SourceCommittish, }, cancellationToken); @@ -954,9 +961,8 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken System.Console.WriteLine("TEST: WATCHDOG BYOND VERSION UPDATE TEST"); var versionToInstall = testVersion; - versionToInstall = versionToInstall.Semver(); var currentByondVersion = await instanceClient.Byond.ActiveVersion(cancellationToken); - Assert.AreNotEqual(versionToInstall, currentByondVersion.Version); + Assert.AreNotEqual(versionToInstall, currentByondVersion); var initialStatus = await instanceClient.DreamDaemon.Read(cancellationToken); @@ -969,7 +975,9 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken var byondInstallJobTask = instanceClient.Byond.SetActiveVersion( new ByondVersionRequest { - Version = versionToInstall + Version = versionToInstall.Version, + Engine = versionToInstall.Engine, + SourceCommittish = versionToInstall.SourceCommittish, }, null, cancellationToken); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index fbfd2d92e6c..0b98971e3eb 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -28,6 +28,7 @@ using Tgstation.Server.Api; using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Api.Rights; @@ -955,7 +956,12 @@ await Task.WhenAny( } [TestMethod] - public async Task TestStandardTgsOperation() + public Task TestStandardTgsOperation() => TestStandardTgsOperation(EngineType.Byond); + + [TestMethod] + public Task TestOpenDreamTgsOperation() => TestStandardTgsOperation(EngineType.OpenDream); + + async Task TestStandardTgsOperation(EngineType engineType) { using(var currentProcess = System.Diagnostics.Process.GetCurrentProcess()) { @@ -980,7 +986,7 @@ public async Task TestStandardTgsOperation() ServiceCollectionExtensions.UseAdditionalLoggerProvider(); var failureTask = HardFailLoggerProvider.FailureSource; - var internalTask = TestTgsInternal(hardCancellationToken); + var internalTask = TestTgsInternal(engineType, hardCancellationToken); await Task.WhenAny( internalTask, failureTask); @@ -1012,7 +1018,7 @@ await Task.WhenAny( await internalTask; } - async Task TestTgsInternal(CancellationToken hardCancellationToken) + async Task TestTgsInternal(EngineType engineType, CancellationToken hardCancellationToken) { var discordConnectionString = Environment.GetEnvironmentVariable("TGS_TEST_DISCORD_TOKEN"); var ircConnectionString = Environment.GetEnvironmentVariable("TGS_TEST_IRC_CONNECTION_STRING"); @@ -1118,7 +1124,7 @@ async Task FailFast(Task task) async Task RunInstanceTests() { // Some earlier linux BYOND versions have a critical bug where replacing the directory in non-basic watchdogs causes the DreamDaemon cwd to change - var canRunCompatTests = new PlatformIdentifier().IsWindows; + var canRunCompatTests = engineType == EngineType.Byond && new PlatformIdentifier().IsWindows; var compatTests = canRunCompatTests ? FailFast( instanceTest @@ -1142,6 +1148,7 @@ await FailFast( mainDDPort, server.HighPriorityDreamDaemon, server.LowPriorityDeployments, + engineType, cancellationToken)); await compatTests; @@ -1308,7 +1315,7 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) preStartupTime = DateTimeOffset.UtcNow; serverTask = server.Run(cancellationToken).AsTask(); long expectedCompileJobId, expectedStaged; - var edgeByond = await ByondTest.GetEdgeVersion(fileDownloader, cancellationToken); + var edgeVersion = await ByondTest.GetEdgeVersion(engineType, fileDownloader, cancellationToken); using (var adminClient = await CreateAdminClient(server.Url, cancellationToken)) { var instanceClient = adminClient.Instances.CreateClient(instance); @@ -1319,7 +1326,7 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value); var compileJob = await instanceClient.DreamMaker.Compile(cancellationToken); - var wdt = new WatchdogTest(edgeByond, instanceClient, GetInstanceManager(), (ushort)server.Url.Port, server.HighPriorityDreamDaemon, mainDDPort); + var wdt = new WatchdogTest(edgeVersion, instanceClient, GetInstanceManager(), (ushort)server.Url.Port, server.HighPriorityDreamDaemon, mainDDPort); await wdt.WaitForJob(compileJob, 30, false, null, cancellationToken); dd = await instanceClient.DreamDaemon.Read(cancellationToken); @@ -1366,7 +1373,7 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest Assert.AreEqual(WatchdogStatus.Online, currentDD.Status); Assert.AreEqual(expectedStaged, currentDD.StagedCompileJob.Job.Id.Value); - var wdt = new WatchdogTest(edgeByond, instanceClient, GetInstanceManager(), (ushort)server.Url.Port, server.HighPriorityDreamDaemon, mainDDPort); + var wdt = new WatchdogTest(edgeVersion, instanceClient, GetInstanceManager(), (ushort)server.Url.Port, server.HighPriorityDreamDaemon, mainDDPort); currentDD = await wdt.TellWorldToReboot(cancellationToken); Assert.AreEqual(expectedStaged, currentDD.ActiveCompileJob.Job.Id.Value); Assert.IsNull(currentDD.StagedCompileJob); diff --git a/tests/Tgstation.Server.Tests/TestDatabase.cs b/tests/Tgstation.Server.Tests/TestDatabase.cs index df8ffd5e4cf..8d629bcfb67 100644 --- a/tests/Tgstation.Server.Tests/TestDatabase.cs +++ b/tests/Tgstation.Server.Tests/TestDatabase.cs @@ -134,7 +134,7 @@ DatabaseContext CreateContext() { new Host.Models.InstancePermissionSet { - ByondRights = ByondRights.InstallCustomVersion, + ByondRights = ByondRights.InstallCustomByondVersion, ChatBotRights = ChatBotRights.None, ConfigurationRights = ConfigurationRights.Read, DreamDaemonRights = DreamDaemonRights.ReadRevision, diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 41c48a1196d..387438b6875 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -28,6 +28,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; using System.Net; +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Api.Models; namespace Tgstation.Server.Tests { @@ -125,12 +127,18 @@ await CachingFileDownloader.InitializeByondVersion( const string ArchiveEntryPath = "byond/bin/dd.exe"; var hasEntry = ArchiveHasFileEntry( - await byondInstaller.DownloadVersion(WindowsByondInstaller.DDExeVersion, default), + await byondInstaller.DownloadVersion( + new ByondVersion + { + Engine = EngineType.Byond, + Version = WindowsByondInstaller.DDExeVersion + }, + default), ArchiveEntryPath); Assert.IsTrue(hasEntry); - var (byondBytes, version) = await GetByondVersionPriorTo(byondInstaller, WindowsByondInstaller.DDExeVersion); + var (byondBytes, _) = await GetByondVersionPriorTo(byondInstaller, WindowsByondInstaller.DDExeVersion); hasEntry = ArchiveHasFileEntry( byondBytes, ArchiveEntryPath); @@ -203,8 +211,18 @@ await CachingFileDownloader.InitializeByondVersion( try { await TestMapThreadsVersion( - ByondInstallerBase.MapThreadsVersion, - await byondInstaller.DownloadVersion(ByondInstallerBase.MapThreadsVersion, default), + new ByondVersion + { + Engine = EngineType.Byond, + Version = ByondInstallerBase.MapThreadsVersion, + }, + await byondInstaller.DownloadVersion( + new ByondVersion + { + Engine = EngineType.Byond, + Version = ByondInstallerBase.MapThreadsVersion + }, + default), byondInstaller, ioManager, processExecutor, @@ -380,22 +398,32 @@ static string GetMigrationTimestampString(Type type) => type Assert.AreEqual(latestMigrationSL, DatabaseContext.SLLatestMigration); } - static async Task> GetByondVersionPriorTo(IByondInstaller byondInstaller, Version version) + static async Task> GetByondVersionPriorTo(IByondInstaller byondInstaller, Version version) { var minusOneMinor = new Version(version.Major, version.Minor - 1); + var byondVersion = new ByondVersion + { + Engine = EngineType.Byond, + Version = minusOneMinor + }; try { - return Tuple.Create(await byondInstaller.DownloadVersion(minusOneMinor, default), minusOneMinor); + return Tuple.Create(await byondInstaller.DownloadVersion( + byondVersion, + CancellationToken.None), byondVersion); } catch (HttpRequestException) { var minusOneMajor = new Version(minusOneMinor.Major - 1, minusOneMinor.Minor); - return Tuple.Create(await byondInstaller.DownloadVersion(minusOneMajor, default), minusOneMajor); + byondVersion.Version = minusOneMajor; + return Tuple.Create(await byondInstaller.DownloadVersion( + byondVersion, + CancellationToken.None), byondVersion); } } static async Task TestMapThreadsVersion( - Version byondVersion, + ByondVersion byondVersion, Stream byondBytes, IByondInstaller byondInstaller, IIOManager ioManager, From 5b468ca0116ac4d91939f5c1ca5e1a8e4c0d5881 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 9 Oct 2023 16:15:00 -0400 Subject: [PATCH 029/717] Move DotnetHelper to Host Common lib Done squashing commits --- .../DotnetHelper.cs | 54 +++++++++++++++++++ .../Watchdog.cs | 52 +++--------------- 2 files changed, 62 insertions(+), 44 deletions(-) create mode 100644 src/Tgstation.Server.Host.Common/DotnetHelper.cs diff --git a/src/Tgstation.Server.Host.Common/DotnetHelper.cs b/src/Tgstation.Server.Host.Common/DotnetHelper.cs new file mode 100644 index 00000000000..b5d80db7844 --- /dev/null +++ b/src/Tgstation.Server.Host.Common/DotnetHelper.cs @@ -0,0 +1,54 @@ +#if NET6_0_OR_GREATER +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +#endif + +namespace Tgstation.Server.Host.Common +{ +#if NET6_0_OR_GREATER + /// + /// Helper functions for working with dotnet.exe. + /// + public static class DotnetHelper + { + /// + /// Gets the path to the dotnet executable. + /// + /// If the current system is a Windows OS. + /// The path to the dotnet executable. + public static IEnumerable GetPotentialDotnetPaths(bool isWindows) + { + var enviromentPath = Environment.GetEnvironmentVariable("PATH"); + var paths = enviromentPath.Split(';'); + + var exeName = "dotnet"; + IEnumerable enumerator; + if (isWindows) + { + exeName += ".exe"; + enumerator = new List(paths) + { + "C:/Program Files/dotnet", + "C:/Program Files (x86)/dotnet", + }; + } + else + enumerator = paths + .Select(x => x.Split(':')) + .SelectMany(x => x) + .Concat(new List(2) + { + "/usr/bin", + "/usr/share/bin", + "/usr/local/share/dotnet", + }); + + enumerator = enumerator.Select(x => Path.Combine(x, exeName)); + + return enumerator; + } + } +#endif +} diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index d5f6456f6f2..bab5e9a07be 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -58,7 +58,14 @@ public async ValueTask RunAsync(bool runConfigure, string[] args, Cancella try { var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var dotnetPath = GetDotnetPath(isWindows); + var dotnetPath = DotnetHelper.GetPotentialDotnetPaths(isWindows) + .Where(potentialDotnetPath => + { + logger.LogTrace("Checking for dotnet at {potentialDotnetPath}", potentialDotnetPath); + return File.Exists(potentialDotnetPath); + }) + .FirstOrDefault(); + if (dotnetPath == default) { logger.LogCritical("Unable to locate dotnet executable in PATH! Please ensure the .NET Core runtime is installed and is in your PATH!"); @@ -350,48 +357,5 @@ public async ValueTask RunAsync(bool runConfigure, string[] args, Cancella } #pragma warning restore CA1502 #pragma warning restore CA1506 - - /// - /// Gets the path to the dotnet executable. - /// - /// If the current system is a Windows OS. - /// The path to the dotnet executable. - string GetDotnetPath(bool isWindows) - { - var enviromentPath = Environment.GetEnvironmentVariable("PATH"); - var paths = enviromentPath.Split(';'); - - var exeName = "dotnet"; - IEnumerable enumerator; - if (isWindows) - { - exeName += ".exe"; - enumerator = new List(paths) - { - "C:/Program Files/dotnet", - "C:/Program Files (x86)/dotnet", - }; - } - else - enumerator = paths - .Select(x => x.Split(':')) - .SelectMany(x => x) - .Concat(new List(2) - { - "/usr/bin", - "/usr/share/bin", - "/usr/local/share/dotnet", - }); - - enumerator = enumerator.Select(x => Path.Combine(x, exeName)); - - return enumerator - .Where(potentialDotnetPath => - { - logger.LogTrace("Checking for dotnet at {potentialDotnetPath}", potentialDotnetPath); - return File.Exists(potentialDotnetPath); - }) - .FirstOrDefault(); - } } } From e5c895fb7310a9f862d27ec9f8b6eddfa4b96ba4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 9 Oct 2023 16:17:55 -0400 Subject: [PATCH 030/717] Rename `ByondManager` to `EngineManager` --- .../{ByondManager.cs => EngineManager.cs} | 16 +++++++------- .../{IByondManager.cs => IEngineManager.cs} | 4 ++-- .../Components/Byond/PosixByondInstaller.cs | 2 +- .../Components/Byond/WindowsByondInstaller.cs | 2 +- .../Components/Chat/Commands/ByondCommand.cs | 22 +++++++++---------- .../Chat/Commands/CommandFactory.cs | 12 +++++----- .../Components/Deployment/DreamMaker.cs | 12 +++++----- .../Components/IInstanceCore.cs | 4 ++-- .../Components/Instance.cs | 14 ++++++------ .../Components/InstanceFactory.cs | 2 +- .../Components/InstanceWrapper.cs | 2 +- .../Session/SessionControllerFactory.cs | 14 ++++++------ .../Controllers/ByondController.cs | 16 +++++++------- .../Live/DummyChatProviderFactory.cs | 2 +- tests/Tgstation.Server.Tests/TestVersions.cs | 2 +- 15 files changed, 63 insertions(+), 63 deletions(-) rename src/Tgstation.Server.Host/Components/Byond/{ByondManager.cs => EngineManager.cs} (97%) rename src/Tgstation.Server.Host/Components/Byond/{IByondManager.cs => IEngineManager.cs} (97%) diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs b/src/Tgstation.Server.Host/Components/Byond/EngineManager.cs similarity index 97% rename from src/Tgstation.Server.Host/Components/Byond/ByondManager.cs rename to src/Tgstation.Server.Host/Components/Byond/EngineManager.cs index 3c6f06c3ad2..a1bf41f3da0 100644 --- a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs +++ b/src/Tgstation.Server.Host/Components/Byond/EngineManager.cs @@ -20,7 +20,7 @@ namespace Tgstation.Server.Host.Components.Byond { /// - sealed class ByondManager : IByondManager + sealed class EngineManager : IEngineManager { /// /// The path to the BYOND bin folder. @@ -66,24 +66,24 @@ public IReadOnlyList InstalledVersions static readonly SemaphoreSlim UserFilesSemaphore = new (1); /// - /// The for the . + /// The for the . /// readonly IIOManager ioManager; /// - /// The for the . + /// The for the . /// readonly IByondInstaller byondInstaller; /// - /// The for the . + /// The for the . /// readonly IEventConsumer eventConsumer; /// - /// The for the . + /// The for the . /// - readonly ILogger logger; + readonly ILogger logger; /// /// Map of byond s to s that complete when they are installed. @@ -116,13 +116,13 @@ static void CheckVersionParameter(ByondVersion version) } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The value of . /// The value of . /// The value of . /// The value of . - public ByondManager(IIOManager ioManager, IByondInstaller byondInstaller, IEventConsumer eventConsumer, ILogger logger) + public EngineManager(IIOManager ioManager, IByondInstaller byondInstaller, IEventConsumer eventConsumer, ILogger logger) { this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.byondInstaller = byondInstaller ?? throw new ArgumentNullException(nameof(byondInstaller)); diff --git a/src/Tgstation.Server.Host/Components/Byond/IByondManager.cs b/src/Tgstation.Server.Host/Components/Byond/IEngineManager.cs similarity index 97% rename from src/Tgstation.Server.Host/Components/Byond/IByondManager.cs rename to src/Tgstation.Server.Host/Components/Byond/IEngineManager.cs index 1da8c041d16..80425fe4a55 100644 --- a/src/Tgstation.Server.Host/Components/Byond/IByondManager.cs +++ b/src/Tgstation.Server.Host/Components/Byond/IEngineManager.cs @@ -11,10 +11,10 @@ namespace Tgstation.Server.Host.Components.Byond { /// - /// For managing the BYOND installation. + /// For managing the engine installations. /// /// When passing in s for , ensure they are BYOND format versions unless referring to a custom version. This means should NEVER be 0. - public interface IByondManager : IComponentService, IDisposable + public interface IEngineManager : IComponentService, IDisposable { /// /// The currently active . diff --git a/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs index 7fed2498ec4..ff094a96366 100644 --- a/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs @@ -99,7 +99,7 @@ async ValueTask WriteAndMakeExecutable(string pathToScript, string script) postWriteHandler.HandleWrite(IOManager.ResolvePath(pathToScript)); } - var basePath = IOManager.ConcatPath(path, ByondManager.BinPath); + var basePath = IOManager.ConcatPath(path, EngineManager.BinPath); var ddTask = WriteAndMakeExecutable( IOManager.ConcatPath(basePath, GetDreamDaemonName(version, out _, out _)), diff --git a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs index 0b177584a4a..ce3e5aad12b 100644 --- a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs @@ -235,7 +235,7 @@ async ValueTask AddDreamDaemonToFirewall(ByondVersion version, string path, Canc var dreamDaemonPath = IOManager.ResolvePath( IOManager.ConcatPath( path, - ByondManager.BinPath, + EngineManager.BinPath, dreamDaemonName)); Logger.LogInformation("Adding Windows Firewall exception for {path}...", dreamDaemonPath); diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs index 8f7b680293d..9cfc07fbd78 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs @@ -25,9 +25,9 @@ sealed class ByondCommand : ICommand public bool AdminOnly => false; /// - /// The for the . + /// The for the . /// - readonly IByondManager byondManager; + readonly IEngineManager engineManager; /// /// The for the . @@ -37,11 +37,11 @@ sealed class ByondCommand : ICommand /// /// Initializes a new instance of the class. /// - /// The value of . + /// The value of . /// The value of . - public ByondCommand(IByondManager byondManager, IWatchdog watchdog) + public ByondCommand(IEngineManager engineManager, IWatchdog watchdog) { - this.byondManager = byondManager ?? throw new ArgumentNullException(nameof(byondManager)); + this.engineManager = engineManager ?? throw new ArgumentNullException(nameof(engineManager)); this.watchdog = watchdog ?? throw new ArgumentNullException(nameof(watchdog)); } @@ -51,22 +51,22 @@ public ValueTask Invoke(string arguments, ChatUser user, Cancell if (arguments.Split(' ').Any(x => x.Equals("--active", StringComparison.OrdinalIgnoreCase))) { string text; - if (byondManager.ActiveVersion == null) + if (engineManager.ActiveVersion == null) text = "None!"; else - switch (byondManager.ActiveVersion.Engine.Value) + switch (engineManager.ActiveVersion.Engine.Value) { case EngineType.OpenDream: - text = $"OpenDream: {byondManager.ActiveVersion.SourceCommittish}"; + text = $"OpenDream: {engineManager.ActiveVersion.SourceCommittish}"; break; case EngineType.Byond: - text = $"BYOND {byondManager.ActiveVersion.Version.Major}.{byondManager.ActiveVersion.Version.Minor}"; - if (byondManager.ActiveVersion.Version.Build != -1) + text = $"BYOND {engineManager.ActiveVersion.Version.Major}.{engineManager.ActiveVersion.Version.Minor}"; + if (engineManager.ActiveVersion.Version.Build != -1) text += " (Custom Build)"; break; default: - throw new InvalidOperationException($"Invalid EngineType: {byondManager.ActiveVersion.Engine.Value}"); + throw new InvalidOperationException($"Invalid EngineType: {engineManager.ActiveVersion.Engine.Value}"); } return ValueTask.FromResult( diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs index 06eb90dd758..d8678fe85ff 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs @@ -19,9 +19,9 @@ sealed class CommandFactory : ICommandFactory readonly IAssemblyInformationProvider assemblyInformationProvider; /// - /// The for the . + /// The for the . /// - readonly IByondManager byondManager; + readonly IEngineManager engineManager; /// /// The for the . @@ -52,21 +52,21 @@ sealed class CommandFactory : ICommandFactory /// Initializes a new instance of the class. /// /// The value of . - /// The value of . + /// The value of . /// The value of . /// The value of . /// The value of . /// The value of . public CommandFactory( IAssemblyInformationProvider assemblyInformationProvider, - IByondManager byondManager, + IEngineManager engineManager, IRepositoryManager repositoryManager, IDatabaseContextFactory databaseContextFactory, ILatestCompileJobProvider compileJobProvider, Models.Instance instance) { this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); - this.byondManager = byondManager ?? throw new ArgumentNullException(nameof(byondManager)); + this.engineManager = engineManager ?? throw new ArgumentNullException(nameof(engineManager)); this.repositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager)); this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.compileJobProvider = compileJobProvider ?? throw new ArgumentNullException(nameof(compileJobProvider)); @@ -92,7 +92,7 @@ public IReadOnlyList GenerateCommands() return new List { new VersionCommand(assemblyInformationProvider), - new ByondCommand(byondManager, watchdog), + new ByondCommand(engineManager, watchdog), new RevisionCommand(watchdog, repositoryManager), new PullRequestsCommand(watchdog, repositoryManager, databaseContextFactory, compileJobProvider, instance), new KekCommand(), diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index d31de3c46f4..c9ea5a5c727 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -41,9 +41,9 @@ sealed class DreamMaker : IDreamMaker const string DmeExtension = "dme"; /// - /// The for . + /// The for . /// - readonly IByondManager byond; + readonly IEngineManager engineManager; /// /// The for . @@ -143,7 +143,7 @@ static string FormatExceptionForUsers(Exception exception) /// /// Initializes a new instance of the class. /// - /// The value of . + /// The value of . /// The value of . /// The value of . /// The value of . @@ -158,7 +158,7 @@ static string FormatExceptionForUsers(Exception exception) /// The value of . /// The value of . public DreamMaker( - IByondManager byond, + IEngineManager engineManager, IIOManager ioManager, StaticFiles.IConfiguration configuration, ISessionControllerFactory sessionControllerFactory, @@ -173,7 +173,7 @@ public DreamMaker( SessionConfiguration sessionConfiguration, Api.Models.Instance metadata) { - this.byond = byond ?? throw new ArgumentNullException(nameof(byond)); + this.engineManager = engineManager ?? throw new ArgumentNullException(nameof(engineManager)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); this.sessionControllerFactory = sessionControllerFactory ?? throw new ArgumentNullException(nameof(sessionControllerFactory)); @@ -482,7 +482,7 @@ await databaseContextFactory.UseContext( var progressTask = ProgressTask(progressReporter, estimatedDuration, progressCts.Token); try { - using var byondLock = await byond.UseExecutables(null, null, cancellationToken); + using var byondLock = await engineManager.UseExecutables(null, null, cancellationToken); currentChatCallback = chatManager.QueueDeploymentMessage( revisionInformation, byondLock.Version, diff --git a/src/Tgstation.Server.Host/Components/IInstanceCore.cs b/src/Tgstation.Server.Host/Components/IInstanceCore.cs index d42b4e69da0..c19dffad829 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceCore.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceCore.cs @@ -20,9 +20,9 @@ public interface IInstanceCore : ILatestCompileJobProvider, IRenameNotifyee IRepositoryManager RepositoryManager { get; } /// - /// The for the . + /// The for the . /// - IByondManager ByondManager { get; } + IEngineManager EngineManager { get; } /// /// The for the . diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 879478a207a..6d9c61e118b 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -36,7 +36,7 @@ sealed class Instance : IInstance public IRepositoryManager RepositoryManager { get; } /// - public IByondManager ByondManager { get; } + public IEngineManager EngineManager { get; } /// public IWatchdog Watchdog { get; } @@ -105,7 +105,7 @@ sealed class Instance : IInstance /// /// The value of . /// The value of . - /// The value of . + /// The value of . /// The value of . /// The value of . /// The value of . @@ -119,7 +119,7 @@ sealed class Instance : IInstance public Instance( Api.Models.Instance metadata, IRepositoryManager repositoryManager, - IByondManager byondManager, + IEngineManager engineManager, IDreamMaker dreamMaker, IWatchdog watchdog, IChatManager chat, @@ -134,7 +134,7 @@ public Instance( { this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); RepositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager)); - ByondManager = byondManager ?? throw new ArgumentNullException(nameof(byondManager)); + EngineManager = engineManager ?? throw new ArgumentNullException(nameof(engineManager)); DreamMaker = dreamMaker ?? throw new ArgumentNullException(nameof(dreamMaker)); Watchdog = watchdog ?? throw new ArgumentNullException(nameof(watchdog)); Chat = chat ?? throw new ArgumentNullException(nameof(chat)); @@ -160,7 +160,7 @@ public async ValueTask DisposeAsync() Configuration.Dispose(); dmbFactory.Dispose(); RepositoryManager.Dispose(); - ByondManager.Dispose(); + EngineManager.Dispose(); await chatDispose; await watchdogDispose; } @@ -185,7 +185,7 @@ public async Task StartAsync(CancellationToken cancellationToken) await Task.WhenAll( SetAutoUpdateInterval(metadata.AutoUpdateInterval.Value).AsTask(), Configuration.StartAsync(cancellationToken), - ByondManager.StartAsync(cancellationToken), + EngineManager.StartAsync(cancellationToken), Chat.StartAsync(cancellationToken), dmbFactory.StartAsync(cancellationToken)); @@ -206,7 +206,7 @@ public async Task StopAsync(CancellationToken cancellationToken) await Watchdog.StopAsync(cancellationToken); await Task.WhenAll( Configuration.StopAsync(cancellationToken), - ByondManager.StopAsync(cancellationToken), + EngineManager.StopAsync(cancellationToken), Chat.StopAsync(cancellationToken), dmbFactory.StopAsync(cancellationToken)); } diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index 6d9d7a8b61c..c0007af8611 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -296,7 +296,7 @@ public async ValueTask CreateInstance(IBridgeRegistrar bridgeRegistra generalConfiguration); try { - var byond = new ByondManager(byondIOManager, byondInstaller, eventConsumer, loggerFactory.CreateLogger()); + var byond = new EngineManager(byondIOManager, byondInstaller, eventConsumer, loggerFactory.CreateLogger()); var dmbFactory = new DmbFactory( databaseContextFactory, diff --git a/src/Tgstation.Server.Host/Components/InstanceWrapper.cs b/src/Tgstation.Server.Host/Components/InstanceWrapper.cs index c8524b50e22..08e2792e01e 100644 --- a/src/Tgstation.Server.Host/Components/InstanceWrapper.cs +++ b/src/Tgstation.Server.Host/Components/InstanceWrapper.cs @@ -25,7 +25,7 @@ sealed class InstanceWrapper : ReferenceCounter, IInstanceReference public IRepositoryManager RepositoryManager => Instance.RepositoryManager; /// - public IByondManager ByondManager => Instance.ByondManager; + public IEngineManager EngineManager => Instance.EngineManager; /// public IDreamMaker DreamMaker => Instance.DreamMaker; diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index e45ed439d62..5a72ee8c015 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -42,9 +42,9 @@ sealed class SessionControllerFactory : ISessionControllerFactory readonly IProcessExecutor processExecutor; /// - /// The for the . + /// The for the . /// - readonly IByondManager byond; + readonly IEngineManager engineManager; /// /// The for the . @@ -147,7 +147,7 @@ void PortBindTest(ushort port) /// Initializes a new instance of the class. /// /// The value of . - /// The value of . + /// The value of . /// The value of . /// The value of . /// The value of . @@ -166,7 +166,7 @@ void PortBindTest(ushort port) /// The value of . public SessionControllerFactory( IProcessExecutor processExecutor, - IByondManager byond, + IEngineManager engineManager, ITopicClientFactory topicClientFactory, ICryptographySuite cryptographySuite, IAssemblyInformationProvider assemblyInformationProvider, @@ -185,7 +185,7 @@ public SessionControllerFactory( Api.Models.Instance instance) { this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); - this.byond = byond ?? throw new ArgumentNullException(nameof(byond)); + this.engineManager = engineManager ?? throw new ArgumentNullException(nameof(engineManager)); this.topicClientFactory = topicClientFactory ?? throw new ArgumentNullException(nameof(topicClientFactory)); this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite)); this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); @@ -239,7 +239,7 @@ public async ValueTask LaunchNew( } // get the byond lock - var byondLock = currentByondLock ?? await byond.UseExecutables( + var byondLock = currentByondLock ?? await engineManager.UseExecutables( dmbProvider.ByondVersion, gameIOManager.ConcatPath(dmbProvider.Directory, dmbProvider.DmbName), cancellationToken); @@ -370,7 +370,7 @@ public async ValueTask Reattach( logger.LogTrace("Begin session reattach..."); var byondTopicSender = topicClientFactory.CreateTopicClient(reattachInformation.TopicRequestTimeout); - var byondLock = await byond.UseExecutables( + var byondLock = await engineManager.UseExecutables( reattachInformation.Dmb.ByondVersion, null, // Doesn't matter if it's trusted or not on reattach cancellationToken); diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index 19212d7c5b0..42732cf6ae0 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -84,10 +84,10 @@ public ByondController( public ValueTask Read() => WithComponentInstance(instance => ValueTask.FromResult( - instance.ByondManager.ActiveVersion != null + instance.EngineManager.ActiveVersion != null ? Json( new ByondResponse( - instance.ByondManager.ActiveVersion)) + instance.EngineManager.ActiveVersion)) : Conflict(new ErrorMessageResponse(ErrorCode.ResourceNotPresent)))); /// @@ -107,7 +107,7 @@ public ValueTask List([FromQuery] int? page, [FromQuery] int? pag () => ValueTask.FromResult( new PaginatableResult( instance - .ByondManager + .EngineManager .InstalledVersions .Select(x => new ByondResponse(x)) .AsQueryable() @@ -169,7 +169,7 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode return await WithComponentInstance( async instance => { - var byondManager = instance.ByondManager; + var byondManager = instance.EngineManager; var versionAlreadyInstalled = !uploadingZip && byondManager.InstalledVersions.Any(x => x.Equals(model)); if (versionAlreadyInstalled) { @@ -231,7 +231,7 @@ await jobManager.RegisterOperation( async (core, databaseContextFactory, paramJob, progressHandler, jobCancellationToken) => { if (sourceRepo != null) - await core.ByondManager.EnsureEngineSource( + await core.EngineManager.EnsureEngineSource( sourceRepo, model.Engine.Value, jobCancellationToken); @@ -254,7 +254,7 @@ await core.ByondManager.EnsureEngineSource( } await using (zipFileStream) - await core.ByondManager.ChangeVersion( + await core.EngineManager.ChangeVersion( progressHandler, model, zipFileStream, @@ -306,7 +306,7 @@ public async ValueTask Delete([FromBody] ByondVersionDeleteReques var notInstalledResponse = await WithComponentInstance( instance => { - var byondManager = instance.ByondManager; + var byondManager = instance.EngineManager; if (model.Equals(byondManager.ActiveVersion)) return ValueTask.FromResult( @@ -343,7 +343,7 @@ public async ValueTask Delete([FromBody] ByondVersionDeleteReques await jobManager.RegisterOperation( job, (instanceCore, databaseContextFactory, job, progressReporter, jobCancellationToken) - => instanceCore.ByondManager.DeleteVersion(progressReporter, model, jobCancellationToken), + => instanceCore.EngineManager.DeleteVersion(progressReporter, model, jobCancellationToken), cancellationToken); var apiResponse = job.ToApi(); diff --git a/tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs b/tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs index d4d7c98b09b..ba12c498ec5 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs @@ -40,7 +40,7 @@ public DummyChatProviderFactory(IJobManager jobManager, ICryptographySuite crypt var commandFactory = new CommandFactory( Mock.Of(), - Mock.Of(), + Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 387438b6875..30d39e2cb9f 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -441,7 +441,7 @@ static async Task TestMapThreadsVersion( var ddPath = ioManager.ConcatPath( tempPath, - ByondManager.BinPath, + EngineManager.BinPath, byondInstaller.GetDreamDaemonName(byondVersion, out var supportsCli, out var shouldSupportMapThreads)); Assert.IsTrue(supportsCli); From c4c656f9828cca29acabef897bd13152949e2aff Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 9 Oct 2023 16:22:21 -0400 Subject: [PATCH 031/717] Rename `IByondInstaller` to `IEngineInstaller`. --- .../Components/Byond/ByondInstallerBase.cs | 4 ++-- .../Components/Byond/EngineManager.cs | 8 ++++---- .../Byond/{IByondInstaller.cs => IEngineInstaller.cs} | 10 +++++----- .../Components/Byond/PosixByondInstaller.cs | 4 ++-- .../Components/Byond/WindowsByondInstaller.cs | 4 ++-- .../Components/InstanceFactory.cs | 6 +++--- src/Tgstation.Server.Host/Core/Application.cs | 4 ++-- .../Components/Byond/TestPosixByondInstaller.cs | 6 +++--- .../Tgstation.Server.Tests/Live/Instance/ByondTest.cs | 2 +- .../Live/Instance/InstanceTest.cs | 2 +- tests/Tgstation.Server.Tests/TestVersions.cs | 8 ++++---- 11 files changed, 29 insertions(+), 29 deletions(-) rename src/Tgstation.Server.Host/Components/Byond/{IByondInstaller.cs => IEngineInstaller.cs} (89%) diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs index 8260eafffaa..d3858a848bc 100644 --- a/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs @@ -12,7 +12,7 @@ namespace Tgstation.Server.Host.Components.Byond { /// - abstract class ByondInstallerBase : IByondInstaller + abstract class ByondInstallerBase : IEngineInstaller { /// /// The name of BYOND's cache directory. @@ -85,7 +85,7 @@ await IOManager.DeleteDirectory( } /// - public abstract ValueTask InstallByond(ByondVersion version, string path, CancellationToken cancellationToken); + public abstract ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken); /// public abstract ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken); diff --git a/src/Tgstation.Server.Host/Components/Byond/EngineManager.cs b/src/Tgstation.Server.Host/Components/Byond/EngineManager.cs index a1bf41f3da0..81f31cbdc3c 100644 --- a/src/Tgstation.Server.Host/Components/Byond/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Byond/EngineManager.cs @@ -71,9 +71,9 @@ public IReadOnlyList InstalledVersions readonly IIOManager ioManager; /// - /// The for the . + /// The for the . /// - readonly IByondInstaller byondInstaller; + readonly IEngineInstaller byondInstaller; /// /// The for the . @@ -122,7 +122,7 @@ static void CheckVersionParameter(ByondVersion version) /// The value of . /// The value of . /// The value of . - public EngineManager(IIOManager ioManager, IByondInstaller byondInstaller, IEventConsumer eventConsumer, ILogger logger) + public EngineManager(IIOManager ioManager, IEngineInstaller byondInstaller, IEventConsumer eventConsumer, ILogger logger) { this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.byondInstaller = byondInstaller ?? throw new ArgumentNullException(nameof(byondInstaller)); @@ -575,7 +575,7 @@ async ValueTask DirectoryCleanup() if (progressReporter != null) progressReporter.StageName = "Running installation actions"; - await byondInstaller.InstallByond(version, installFullPath, cancellationToken); + await byondInstaller.Install(version, installFullPath, cancellationToken); if (progressReporter != null) progressReporter.StageName = "Writing version file"; diff --git a/src/Tgstation.Server.Host/Components/Byond/IByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/IEngineInstaller.cs similarity index 89% rename from src/Tgstation.Server.Host/Components/Byond/IByondInstaller.cs rename to src/Tgstation.Server.Host/Components/Byond/IEngineInstaller.cs index b1a89bd48ce..8fadfb0c787 100644 --- a/src/Tgstation.Server.Host/Components/Byond/IByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/IEngineInstaller.cs @@ -7,9 +7,9 @@ namespace Tgstation.Server.Host.Components.Byond { /// - /// For downloading and installing BYOND extractions for a given system. + /// For downloading and installing game engines for a given system. /// - interface IByondInstaller + interface IEngineInstaller { /// /// Get the file name of the compiler executable. @@ -31,7 +31,7 @@ interface IByondInstaller string GetDreamDaemonName(ByondVersion version, out bool supportsCli, out bool supportsMapThreads); /// - /// Download a given BYOND . + /// Download a given engine . /// /// The of BYOND to download. /// The for the operation. @@ -39,13 +39,13 @@ interface IByondInstaller ValueTask DownloadVersion(ByondVersion version, CancellationToken cancellationToken); /// - /// Does actions necessary to get an extracted BYOND installation working. + /// Does actions necessary to get an extracted installation working. /// /// The being installed. /// The path to the BYOND installation. /// The for the operation. /// A representing the running operation. - ValueTask InstallByond(ByondVersion version, string path, CancellationToken cancellationToken); + ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken); /// /// Does actions necessary to get upgrade a BYOND version installed by a previous version of TGS. diff --git a/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs index ff094a96366..4e657994eec 100644 --- a/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs @@ -13,7 +13,7 @@ namespace Tgstation.Server.Host.Components.Byond { /// - /// for Posix systems. + /// for Posix systems. /// sealed class PosixByondInstaller : ByondInstallerBase { @@ -80,7 +80,7 @@ public override string GetDreamDaemonName(ByondVersion version, out bool support } /// - public override ValueTask InstallByond(ByondVersion version, string path, CancellationToken cancellationToken) + public override ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(version); ArgumentNullException.ThrowIfNull(path); diff --git a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs index ce3e5aad12b..da9105d5b5c 100644 --- a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs @@ -19,7 +19,7 @@ namespace Tgstation.Server.Host.Components.Byond { /// - /// for windows systems. + /// for windows systems. /// sealed class WindowsByondInstaller : ByondInstallerBase, IDisposable { @@ -125,7 +125,7 @@ public override string GetDreamDaemonName(ByondVersion version, out bool support } /// - public override ValueTask InstallByond(ByondVersion version, string path, CancellationToken cancellationToken) + public override ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken) { var tasks = new List(3) { diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index c0007af8611..0533ee0270b 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -71,9 +71,9 @@ sealed class InstanceFactory : IInstanceFactory readonly ISymlinkFactory symlinkFactory; /// - /// The for the . + /// The for the . /// - readonly IByondInstaller byondInstaller; + readonly IEngineInstaller byondInstaller; /// /// The for the . @@ -200,7 +200,7 @@ public InstanceFactory( ICryptographySuite cryptographySuite, ISynchronousIOManager synchronousIOManager, ISymlinkFactory symlinkFactory, - IByondInstaller byondInstaller, + IEngineInstaller byondInstaller, IChatManagerFactory chatFactory, IProcessExecutor processExecutor, IPostWriteHandler postWriteHandler, diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index da0a804468b..6cee39ad160 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -332,7 +332,7 @@ void AddTypedContext() AddWatchdog(services, postSetupServices); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -345,7 +345,7 @@ void AddTypedContext() AddWatchdog(services, postSetupServices); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs index c57e72afa16..8ce2d11787d 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs @@ -84,7 +84,7 @@ public async Task TestInstallByond() var installer = new PosixByondInstaller(mockPostWriteHandler.Object, mockIOManager.Object, mockFileDownloader, mockLogger.Object); const string FakePath = "fake"; - await Assert.ThrowsExceptionAsync(() => installer.InstallByond(null, null, default).AsTask()); + await Assert.ThrowsExceptionAsync(() => installer.Install(null, null, default).AsTask()); var byondVersion = new ByondVersion { @@ -92,10 +92,10 @@ public async Task TestInstallByond() Version = new Version(123, 252345), }; - await Assert.ThrowsExceptionAsync(() => installer.InstallByond(byondVersion, null, default).AsTask()); + await Assert.ThrowsExceptionAsync(() => installer.Install(byondVersion, null, default).AsTask()); byondVersion.Version = new Version(511, 1385); - await installer.InstallByond(byondVersion, FakePath, default); + await installer.Install(byondVersion, FakePath, default); mockPostWriteHandler.Verify(x => x.HandleWrite(It.IsAny()), Times.Exactly(4)); } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index 3e9f5ca84c9..3010f92e880 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -241,7 +241,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) var assemblyInformationProvider = new AssemblyInformationProvider(); - IByondInstaller byondInstaller = new PlatformIdentifier().IsWindows + IEngineInstaller byondInstaller = new PlatformIdentifier().IsWindows ? new WindowsByondInstaller( Mock.Of(), Mock.Of(), diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index ea17e68033d..22dc9edec89 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -141,7 +141,7 @@ public async Task RunCompatTests( var jrt = new JobsRequiredTest(instanceClient.Jobs); - IByondInstaller byondInstaller = new PlatformIdentifier().IsWindows + IEngineInstaller byondInstaller = new PlatformIdentifier().IsWindows ? new WindowsByondInstaller( Mock.Of(), Mock.Of(), diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 30d39e2cb9f..2268852074c 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -179,7 +179,7 @@ await CachingFileDownloader.InitializeByondVersion( var fileDownloader = new CachingFileDownloader(Mock.Of>()); - IByondInstaller byondInstaller = platformIdentifier.IsWindows + IEngineInstaller byondInstaller = platformIdentifier.IsWindows ? new WindowsByondInstaller( Mock.Of(), Mock.Of(), @@ -398,7 +398,7 @@ static string GetMigrationTimestampString(Type type) => type Assert.AreEqual(latestMigrationSL, DatabaseContext.SLLatestMigration); } - static async Task> GetByondVersionPriorTo(IByondInstaller byondInstaller, Version version) + static async Task> GetByondVersionPriorTo(IEngineInstaller byondInstaller, Version version) { var minusOneMinor = new Version(version.Major, version.Minor - 1); var byondVersion = new ByondVersion @@ -425,7 +425,7 @@ static async Task> GetByondVersionPriorTo(IByo static async Task TestMapThreadsVersion( ByondVersion byondVersion, Stream byondBytes, - IByondInstaller byondInstaller, + IEngineInstaller byondInstaller, IIOManager ioManager, IProcessExecutor processExecutor, string tempPath) @@ -437,7 +437,7 @@ static async Task TestMapThreadsVersion( if (byondInstaller.GetType() == typeof(WindowsByondInstaller)) typeof(WindowsByondInstaller).GetField("installedDirectX", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(byondInstaller, true); - await byondInstaller.InstallByond(byondVersion, tempPath, default); + await byondInstaller.Install(byondVersion, tempPath, default); var ddPath = ioManager.ConcatPath( tempPath, From 809ba413a78c52b1b79021ee9995af38550727c4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 9 Oct 2023 18:46:10 -0400 Subject: [PATCH 032/717] Implement most of OpenDreamInstaller Drop support for custom OD repositories, hopefully fix custom installs. Need to go back to the git strat because of submodules --- src/Tgstation.Server.Api/Models/ErrorCode.cs | 6 +- .../Models/Internal/ByondVersion.cs | 4 +- .../Models/Request/ByondVersionRequest.cs | 9 +- .../Components/Byond/ByondInstallerBase.cs | 175 ++++++++++++++---- .../Components/Byond/EngineInstallerBase.cs | 98 ++++++++++ .../Components/Byond/EngineManager.cs | 144 +------------- .../Components/Byond/IEngineInstaller.cs | 35 ++-- .../Components/Byond/IEngineManager.cs | 9 - .../Components/Byond/OpenDreamInstaller.cs | 131 +++++++++++++ .../Components/Byond/PosixByondInstaller.cs | 31 ++-- .../Components/Byond/WindowsByondInstaller.cs | 40 ++-- .../Components/InstanceFactory.cs | 12 +- .../Controllers/ByondController.cs | 21 +-- .../Utils/GitHub/GitHubService.cs | 18 ++ .../Utils/GitHub/IGitHubService.cs | 10 + tests/Tgstation.Server.Tests/TestVersions.cs | 33 ++-- 16 files changed, 491 insertions(+), 285 deletions(-) create mode 100644 src/Tgstation.Server.Host/Components/Byond/EngineInstallerBase.cs create mode 100644 src/Tgstation.Server.Host/Components/Byond/OpenDreamInstaller.cs diff --git a/src/Tgstation.Server.Api/Models/ErrorCode.cs b/src/Tgstation.Server.Api/Models/ErrorCode.cs index e10d4577c84..9b51e8f9bb7 100644 --- a/src/Tgstation.Server.Api/Models/ErrorCode.cs +++ b/src/Tgstation.Server.Api/Models/ErrorCode.cs @@ -629,6 +629,10 @@ public enum ErrorCode : uint [Description("The deployment took longer than the configured timeout!")] DeploymentTimeout, - // This comment is here to remind you that there is one more unused error code above and you should use it first + /// + /// Could not compile OpenDream due to a missing dotnet executable. + /// + [Description("OpenDream could not be compiled due to being unable to locate the dotnet executable!")] + OpenDreamCantFindDotnet, } } diff --git a/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs b/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs index 8526d159b62..04e42bc7e41 100644 --- a/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs +++ b/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs @@ -16,13 +16,13 @@ public class ByondVersion : IEquatable public EngineType? Engine { get; set; } /// - /// The of the engine. + /// The of the engine. Currently only valid when is . /// [ResponseOptions] public Version? Version { get; set; } /// - /// The git committish of the . On response, this will always be a commit SHA. + /// The git committish of the engine. On response, this will always be a commit SHA. Currently only valid when is . /// [ResponseOptions] [StringLength(Limits.MaximumCommitShaLength)] diff --git a/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs b/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs index a04dfd0d7e1..a7d86f8e79e 100644 --- a/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs @@ -1,6 +1,4 @@ -using System; - -using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Api.Models.Internal; namespace Tgstation.Server.Api.Models.Request { @@ -13,10 +11,5 @@ public sealed class ByondVersionRequest : ByondVersion /// If a custom BYOND version is to be uploaded. /// public bool? UploadCustomZip { get; set; } - - /// - /// The remote repository for non- s. By default, this is the original git repository of the target . - /// - public Uri? SourceRepository { get; set; } } } diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs index d3858a848bc..7c094041bcb 100644 --- a/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs @@ -1,107 +1,202 @@ using System; using System.Globalization; -using System.IO; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.Components.Byond { - /// - abstract class ByondInstallerBase : IEngineInstaller + /// + /// Base implementation of for . + /// + abstract class ByondInstallerBase : EngineInstallerBase { + /// + /// The path to the BYOND bin folder. + /// + protected const string BinPath = "byond/bin"; + /// /// The name of BYOND's cache directory. /// const string CacheDirectoryName = "cache"; /// - /// The first of BYOND that supports the '-map-threads' parameter on DreamDaemon. + /// The path to the cfg directory. /// - public static Version MapThreadsVersion => new (515, 1609); + const string CfgDirectoryName = "cfg"; - /// - public abstract string CompilerName { get; } + /// + /// The name of the list of trusted .dmb files in the user's BYOND cfg directory. + /// + const string TrustedDmbFileName = "trusted.txt"; - /// - public abstract string PathToUserFolder { get; } + /// + /// The first of BYOND that supports the '-map-threads' parameter on DreamDaemon. + /// + static readonly Version MapThreadsVersion = new (515, 1609); /// - /// Gets the URL formatter string for downloading a byond version of {0:Major} {1:Minor}. + /// for writing to files in the user's BYOND directory. /// - protected abstract string ByondRevisionsUrlTemplate { get; } + static readonly SemaphoreSlim UserFilesSemaphore = new (1); + + /// + protected override EngineType TargetEngineType => EngineType.Byond; /// - /// Gets the for the . + /// Bath to the system user's local BYOND folder. /// - protected IIOManager IOManager { get; } + protected abstract string PathToUserFolder { get; } /// - /// Gets the for the . + /// Path to the DreamMaker executable. /// - protected ILogger Logger { get; } + protected abstract string DreamMakerName { get; } /// - /// The for the . + /// Gets the URL formatter string for downloading a byond version of {0:Major} {1:Minor}. /// - readonly IFileDownloader fileDownloader; + protected abstract string ByondRevisionsUrlTemplate { get; } /// /// Initializes a new instance of the class. /// - /// The value of . - /// The value of . - /// The value of . + /// The for the . + /// The for the . + /// The for the . protected ByondInstallerBase(IIOManager ioManager, IFileDownloader fileDownloader, ILogger logger) + : base(ioManager, fileDownloader, logger) { - IOManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); - this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); - Logger = logger ?? throw new ArgumentNullException(nameof(logger)); } /// - public abstract string GetDreamDaemonName(ByondVersion version, out bool supportsCli, out bool supportsMapThreads); + public override IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask) + { + CheckVersionValidity(version); + + var binPathForVersion = IOManager.ConcatPath(version.ToString(), BinPath); + var supportsMapThreads = version.Version >= MapThreadsVersion; + + return new ByondInstallation( + installationTask, + version, + IOManager.ResolvePath( + IOManager.ConcatPath( + binPathForVersion, + GetDreamDaemonName( + version.Version, + out var supportsCli))), + IOManager.ResolvePath( + IOManager.ConcatPath( + binPathForVersion, + DreamMakerName)), + supportsCli, + supportsMapThreads); + } /// - public async Task CleanCache(CancellationToken cancellationToken) + public override async Task CleanCache(CancellationToken cancellationToken) { try { + var byondDir = PathToUserFolder; + Logger.LogDebug("Cleaning BYOND cache..."); - await IOManager.DeleteDirectory( + var cacheCleanTask = IOManager.DeleteDirectory( IOManager.ConcatPath( - PathToUserFolder, + byondDir, CacheDirectoryName), cancellationToken); + + // Create local cfg directory in case it doesn't exist + var localCfgDirectory = IOManager.ConcatPath( + byondDir, + CfgDirectoryName); + + var cfgCreateTask = IOManager.CreateDirectory( + localCfgDirectory, + cancellationToken); + + // Delete trusted.txt so it doesn't grow too large + var trustedFilePath = + IOManager.ConcatPath( + localCfgDirectory, + TrustedDmbFileName); + + Logger.LogTrace("Deleting trusted .dmbs file {trustedFilePath}", trustedFilePath); + var trustedDmbDeleteTask = IOManager.DeleteFile( + trustedFilePath, + cancellationToken); + + await Task.WhenAll(cacheCleanTask, cfgCreateTask, trustedDmbDeleteTask); } catch (Exception ex) when (ex is not OperationCanceledException) { - Logger.LogWarning(ex, "Error deleting BYOND cache!"); + Logger.LogWarning(ex, "Error cleaning BYOND cache!"); } } /// - public abstract ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken); + public override async ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken) + { + var byondDir = PathToUserFolder; + if (String.IsNullOrWhiteSpace(byondDir)) + { + Logger.LogTrace("No relevant user BYOND directory to install a \"{fileName}\" in", TrustedDmbFileName); + return; + } - /// - public abstract ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken); + var trustedFilePath = IOManager.ConcatPath( + byondDir, + CfgDirectoryName, + TrustedDmbFileName); + + Logger.LogDebug("Adding .dmb ({dmbPath}) to {trustedFilePath}", fullDmbPath, trustedFilePath); + + using (await SemaphoreSlimContext.Lock(UserFilesSemaphore, cancellationToken)) + { + string trustedFileText; + if (await IOManager.FileExists(trustedFilePath, cancellationToken)) + { + var trustedFileBytes = await IOManager.ReadAllBytes(trustedFilePath, cancellationToken); + trustedFileText = Encoding.UTF8.GetString(trustedFileBytes); + trustedFileText = $"{trustedFileText.Trim()}{Environment.NewLine}"; + } + else + trustedFileText = String.Empty; + + if (trustedFileText.Contains(fullDmbPath, StringComparison.Ordinal)) + return; + + trustedFileText = $"{trustedFileText}{fullDmbPath}{Environment.NewLine}"; + + var newTrustedFileBytes = Encoding.UTF8.GetBytes(trustedFileText); + await IOManager.WriteAllBytes(trustedFilePath, newTrustedFileBytes, cancellationToken); + } + } /// - public async ValueTask DownloadVersion(ByondVersion version, CancellationToken cancellationToken) + protected override ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken) { - ArgumentNullException.ThrowIfNull(version); - - Logger.LogTrace("Downloading BYOND version {major}.{minor}...", version.Version.Major, version.Version.Minor); + CheckVersionValidity(version); var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Version.Major, version.Version.Minor); - - await using var download = fileDownloader.DownloadFile(new Uri(url), null); - await using var buffer = new BufferedFileStreamProvider( - await download.GetResult(cancellationToken)); - return await buffer.GetOwnedResult(cancellationToken); + return ValueTask.FromResult(new Uri(url)); } + + /// + /// Get the file name of the DreamDaemon executable. + /// + /// The of BYOND to select the executable name for. + /// Whether or not the returned path supports being run as a command-line application. + /// The file name of the DreamDaemon executable. + protected abstract string GetDreamDaemonName(Version byondVersion, out bool supportsCli); } } diff --git a/src/Tgstation.Server.Host/Components/Byond/EngineInstallerBase.cs b/src/Tgstation.Server.Host/Components/Byond/EngineInstallerBase.cs new file mode 100644 index 00000000000..eef9da9ea78 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Byond/EngineInstallerBase.cs @@ -0,0 +1,98 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.Extensions.Logging; + +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.IO; + +namespace Tgstation.Server.Host.Components.Byond +{ + /// + abstract class EngineInstallerBase : IEngineInstaller + { + /// + /// The the installer supports. + /// + protected abstract EngineType TargetEngineType { get; } + + /// + /// Gets the for the . + /// + protected IIOManager IOManager { get; } + + /// + /// Gets the for the . + /// + protected ILogger Logger { get; } + + /// + /// The for the . + /// + readonly IFileDownloader fileDownloader; + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + /// The value of . + protected EngineInstallerBase(IIOManager ioManager, IFileDownloader fileDownloader, ILogger logger) + { + IOManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); + Logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + public abstract IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask); + + /// + public abstract Task CleanCache(CancellationToken cancellationToken); + + /// + public abstract ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken); + + /// + public abstract ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken); + + /// + public async ValueTask DownloadVersion(ByondVersion version, CancellationToken cancellationToken) + { + CheckVersionValidity(version); + + var url = await GetDownloadZipUrl(version, cancellationToken); + Logger.LogTrace("Downloading {engineType} version {version} from {url}...", TargetEngineType, version, url); + + await using var download = fileDownloader.DownloadFile(url, null); + await using var buffer = new BufferedFileStreamProvider( + await download.GetResult(cancellationToken)); + return await buffer.GetOwnedResult(cancellationToken); + } + + /// + public abstract ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken); + + /// + /// Create a pointing to the location of the download for a given . + /// + /// The to create a for. + /// The for the operation. + /// A resulting in a new pointing to the version download location. + protected abstract ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken); + + /// + /// Check that a given is of type . + /// + /// The to check. + protected void CheckVersionValidity(ByondVersion version) + { + ArgumentNullException.ThrowIfNull(version); + if (version.Engine.Value != TargetEngineType) + throw new InvalidOperationException($"Non-{TargetEngineType} engine specified: {version.Engine.Value}"); + } + } +} diff --git a/src/Tgstation.Server.Host/Components/Byond/EngineManager.cs b/src/Tgstation.Server.Host/Components/Byond/EngineManager.cs index 81f31cbdc3c..b60610d1175 100644 --- a/src/Tgstation.Server.Host/Components/Byond/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Byond/EngineManager.cs @@ -22,21 +22,6 @@ namespace Tgstation.Server.Host.Components.Byond /// sealed class EngineManager : IEngineManager { - /// - /// The path to the BYOND bin folder. - /// - public const string BinPath = "byond/bin"; - - /// - /// The path to the cfg directory. - /// - const string CfgDirectoryName = "cfg"; - - /// - /// The name of the list of trusted .dmb files in the user's BYOND cfg directory. - /// - const string TrustedDmbFileName = "trusted.txt"; - /// /// The file in which we store the for installations. /// @@ -60,11 +45,6 @@ public IReadOnlyList InstalledVersions } } - /// - /// for writing to files in the user's BYOND directory. - /// - static readonly SemaphoreSlim UserFilesSemaphore = new (1); - /// /// The for the . /// @@ -73,7 +53,7 @@ public IReadOnlyList InstalledVersions /// /// The for the . /// - readonly IEngineInstaller byondInstaller; + readonly IEngineInstaller engineInstaller; /// /// The for the . @@ -119,13 +99,13 @@ static void CheckVersionParameter(ByondVersion version) /// Initializes a new instance of the class. /// /// The value of . - /// The value of . + /// The value of . /// The value of . /// The value of . - public EngineManager(IIOManager ioManager, IEngineInstaller byondInstaller, IEventConsumer eventConsumer, ILogger logger) + public EngineManager(IIOManager ioManager, IEngineInstaller engineInstaller, IEventConsumer eventConsumer, ILogger logger) { this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); - this.byondInstaller = byondInstaller ?? throw new ArgumentNullException(nameof(byondInstaller)); + this.engineInstaller = engineInstaller ?? throw new ArgumentNullException(nameof(engineInstaller)); this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -200,7 +180,7 @@ public async ValueTask UseExecutables(ByondVersion requir try { if (trustDmbFullPath != null) - await TrustDmbPath(trustDmbFullPath, cancellationToken); + await engineInstaller.TrustDmbPath(trustDmbFullPath, cancellationToken); return installLock; } @@ -301,13 +281,6 @@ await ioManager.DeleteFile( } } - /// - public async ValueTask EnsureEngineSource(Uri source, EngineType engine, CancellationToken cancellationToken) - { - await Task.Yield(); - throw new NotImplementedException(); - } - /// public async Task StartAsync(CancellationToken cancellationToken) { @@ -319,29 +292,6 @@ async ValueTask GetActiveVersion() var activeVersionBytesTask = GetActiveVersion(); - var byondDir = byondInstaller.PathToUserFolder; - if (byondDir != null) - using (await SemaphoreSlimContext.Lock(UserFilesSemaphore, cancellationToken)) - { - // Create local cfg directory in case it doesn't exist - var localCfgDirectory = ioManager.ConcatPath( - byondDir, - CfgDirectoryName); - await ioManager.CreateDirectory( - localCfgDirectory, - cancellationToken); - - // Delete trusted.txt so it doesn't grow too large - var trustedFilePath = - ioManager.ConcatPath( - localCfgDirectory, - TrustedDmbFileName); - logger.LogTrace("Deleting trusted .dmbs file {trustedFilePath}", trustedFilePath); - await ioManager.DeleteFile( - trustedFilePath, - cancellationToken); - } - await ioManager.CreateDirectory(DefaultIOManager.CurrentDirectory, cancellationToken); var directories = await ioManager.GetDirectories(DefaultIOManager.CurrentDirectory, cancellationToken); @@ -393,7 +343,7 @@ await ValueTaskExtensions.WhenAll( logger.LogTrace("Upgrading BYOND installations..."); await ValueTaskExtensions.WhenAll( installedVersionPaths - .Select(kvp => byondInstaller.UpgradeInstallation(kvp.Value, kvp.Key, cancellationToken))); + .Select(kvp => engineInstaller.UpgradeInstallation(kvp.Value, kvp.Key, cancellationToken))); var activeVersionBytes = await activeVersionBytesTask; if (activeVersionBytes != null) @@ -553,7 +503,7 @@ async ValueTask DirectoryCleanup() if (progressReporter != null) progressReporter.StageName = "Downloading version"; - versionZipStream = await byondInstaller.DownloadVersion(version, cancellationToken); + versionZipStream = await engineInstaller.DownloadVersion(version, cancellationToken); } else versionZipStream = customVersionStream; @@ -575,7 +525,7 @@ async ValueTask DirectoryCleanup() if (progressReporter != null) progressReporter.StageName = "Running installation actions"; - await byondInstaller.Install(version, installFullPath, cancellationToken); + await engineInstaller.Install(version, installFullPath, cancellationToken); if (progressReporter != null) progressReporter.StageName = "Writing version file"; @@ -607,40 +557,10 @@ await ioManager.WriteAllBytes( /// /// The being added. /// The representing the installation process. - /// The new containing the new . + /// The new . ReferenceCountingContainer AddInstallationContainer(ByondVersion version, Task installationTask) { - var binPathForVersion = ioManager.ConcatPath(version.ToString(), BinPath); - IEngineInstallation installation; - - switch (version.Engine.Value) - { - case EngineType.Byond: - installation = new ByondInstallation( - installationTask, - version, - ioManager.ResolvePath( - ioManager.ConcatPath( - binPathForVersion, - byondInstaller.GetDreamDaemonName( - version, - out var supportsCli, - out var supportsMapThreads))), - ioManager.ResolvePath( - ioManager.ConcatPath( - binPathForVersion, - byondInstaller.CompilerName)), - supportsCli, - supportsMapThreads); - break; - case EngineType.OpenDream: - installation = new OpenDreamInstallation( - installationTask, - version); - break; - default: - throw new InvalidOperationException($"Invalid EngineType: {version.Engine.Value}"); - } + var installation = engineInstaller.CreateInstallation(version, installationTask); var installationContainer = new ReferenceCountingContainer(installation); @@ -649,49 +569,5 @@ ReferenceCountingContainer AddInstall return installationContainer; } - - /// - /// Add a given to the trusted DMBs list in BYOND's config. - /// - /// Full path to the .dmb that should be trusted. - /// The for the operation. - /// A representing the running operation. - async ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken) - { - var byondDir = byondInstaller.PathToUserFolder; - if (String.IsNullOrWhiteSpace(byondDir)) - { - logger.LogTrace("No relevant user BYOND directory to install a \"{fileName}\" in", TrustedDmbFileName); - return; - } - - var trustedFilePath = ioManager.ConcatPath( - byondDir, - CfgDirectoryName, - TrustedDmbFileName); - - logger.LogDebug("Adding .dmb ({dmbPath}) to {trustedFilePath}", fullDmbPath, trustedFilePath); - - using (await SemaphoreSlimContext.Lock(UserFilesSemaphore, cancellationToken)) - { - string trustedFileText; - if (await ioManager.FileExists(trustedFilePath, cancellationToken)) - { - var trustedFileBytes = await ioManager.ReadAllBytes(trustedFilePath, cancellationToken); - trustedFileText = Encoding.UTF8.GetString(trustedFileBytes); - trustedFileText = $"{trustedFileText.Trim()}{Environment.NewLine}"; - } - else - trustedFileText = String.Empty; - - if (trustedFileText.Contains(fullDmbPath, StringComparison.Ordinal)) - return; - - trustedFileText = $"{trustedFileText}{fullDmbPath}{Environment.NewLine}"; - - var newTrustedFileBytes = Encoding.UTF8.GetBytes(trustedFileText); - await ioManager.WriteAllBytes(trustedFilePath, newTrustedFileBytes, cancellationToken); - } - } } } diff --git a/src/Tgstation.Server.Host/Components/Byond/IEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/IEngineInstaller.cs index 8fadfb0c787..9f389e84747 100644 --- a/src/Tgstation.Server.Host/Components/Byond/IEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/IEngineInstaller.cs @@ -12,23 +12,12 @@ namespace Tgstation.Server.Host.Components.Byond interface IEngineInstaller { /// - /// Get the file name of the compiler executable. + /// Creates an for a given . /// - string CompilerName { get; } - - /// - /// The path to the folder for the user's data. - /// - string PathToUserFolder { get; } - - /// - /// Get the file name of the DreamDaemon executable. - /// - /// The of BYOND to select the executable name for. - /// Whether or not the returned path supports being run as a command-line application. - /// Whether or not the returned path supports the '-map-threads' parameter. - /// The file name of the DreamDaemon executable. - string GetDreamDaemonName(ByondVersion version, out bool supportsCli, out bool supportsMapThreads); + /// The of the installation. + /// The representing the installation process for the installation. + /// The . + IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask); /// /// Download a given engine . @@ -42,20 +31,28 @@ interface IEngineInstaller /// Does actions necessary to get an extracted installation working. /// /// The being installed. - /// The path to the BYOND installation. + /// The path to the installation. /// The for the operation. /// A representing the running operation. ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken); /// - /// Does actions necessary to get upgrade a BYOND version installed by a previous version of TGS. + /// Does actions necessary to get upgrade a version installed by a previous version of TGS. /// /// The being installed. - /// The path to the BYOND installation. + /// The path to the installation. /// The for the operation. /// A representing the running operation. ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken); + /// + /// Add a given to the trusted DMBs list in BYOND's config. + /// + /// Full path to the .dmb that should be trusted. + /// The for the operation. + /// A representing the running operation. + ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken); + /// /// Attempts to cleans the engine's cache folder for the system. /// diff --git a/src/Tgstation.Server.Host/Components/Byond/IEngineManager.cs b/src/Tgstation.Server.Host/Components/Byond/IEngineManager.cs index 80425fe4a55..a336b1f5077 100644 --- a/src/Tgstation.Server.Host/Components/Byond/IEngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Byond/IEngineManager.cs @@ -26,15 +26,6 @@ public interface IEngineManager : IComponentService, IDisposable /// IReadOnlyList InstalledVersions { get; } - /// - /// Ensure that the given is registered for the given . - /// - /// The source of the . - /// The . - /// The for the operation. - /// A representing the running operation. - ValueTask EnsureEngineSource(Uri source, EngineType engine, CancellationToken cancellationToken); - /// /// Change the active . /// diff --git a/src/Tgstation.Server.Host/Components/Byond/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/OpenDreamInstaller.cs new file mode 100644 index 00000000000..53786bfb6a8 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Byond/OpenDreamInstaller.cs @@ -0,0 +1,131 @@ +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.Extensions.Logging; + +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Common; +using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.Jobs; +using Tgstation.Server.Host.System; +using Tgstation.Server.Host.Utils.GitHub; + +namespace Tgstation.Server.Host.Components.Byond +{ + /// + /// Implementation of for . + /// + sealed class OpenDreamInstaller : EngineInstallerBase + { + /// + protected override EngineType TargetEngineType => EngineType.OpenDream; + + /// + /// The for the . + /// + readonly IPlatformIdentifier platformIdentifier; + + /// + /// The for the . + /// + readonly IGitHubService gitHubService; + + /// + /// The for the . + /// + readonly IProcessExecutor processExecutor; + + /// + /// Initializes a new instance of the class. + /// + /// The for the . + /// The for the . + /// The for the . + /// The value of . + /// The value of . + /// The value of . + public OpenDreamInstaller( + IIOManager ioManager, + IFileDownloader fileDownloader, + ILogger logger, + IPlatformIdentifier platformIdentifier, + IGitHubService gitHubService, + IProcessExecutor processExecutor) + : base(ioManager, fileDownloader, logger) + { + this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); + this.gitHubService = gitHubService ?? throw new ArgumentNullException(nameof(gitHubService)); + this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); + } + + /// + public override Task CleanCache(CancellationToken cancellationToken) => Task.CompletedTask; + + /// + public override IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask) + { + CheckVersionValidity(version); + return new OpenDreamInstallation(installationTask, version); + } + + /// + public override async ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken) + { + CheckVersionValidity(version); + ArgumentNullException.ThrowIfNull(path); + + var dotnetPaths = DotnetHelper.GetPotentialDotnetPaths(platformIdentifier.IsWindows) + .ToList(); + var tasks = dotnetPaths + .Select(path => IOManager.FileExists(path, cancellationToken)) + .ToList(); + + await Task.WhenAll(tasks); + + var selectedPathIndex = tasks.FindIndex(pathValidTask => pathValidTask.Result); + + if (selectedPathIndex == -1) + throw new JobException(ErrorCode.OpenDreamCantFindDotnet); + + var dotnetPath = dotnetPaths[selectedPathIndex]; + + await Task.Yield(); + throw new NotImplementedException(); + } + + /// + public override ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken) + { + CheckVersionValidity(version); + ArgumentNullException.ThrowIfNull(path); + return ValueTask.CompletedTask; + } + + /// + public override ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(fullDmbPath); + return ValueTask.CompletedTask; + } + + /// + protected override async ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken) + { + throw new NotImplementedException("This won't work because of the goddamn fucking robust toolbox submodule"); + + var fullCommit = await gitHubService.GetCommit("OpenDreamProject", "OpenDream", version.SourceCommittish, cancellationToken); + + if (fullCommit.Sha != version.SourceCommittish) + { + Logger.LogInformation("Replacing committish {committish} with full SHA {sha}...", version.SourceCommittish, fullCommit.Sha); + version.SourceCommittish = fullCommit.Sha; + } + + var gitHubDownloadUrlString = $"https://codeload.github.com/OpenDreamProject/OpenDream/zip/{version.SourceCommittish}"; + return new Uri(gitHubDownloadUrlString); + } + } +} diff --git a/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs index 4e657994eec..b9015eddd8f 100644 --- a/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs @@ -33,10 +33,10 @@ sealed class PosixByondInstaller : ByondInstallerBase const string ShellScriptExtension = ".sh"; /// - public override string CompilerName => DreamMakerExecutableName + ShellScriptExtension; + protected override string PathToUserFolder { get; } /// - public override string PathToUserFolder { get; } + protected override string DreamMakerName => DreamMakerExecutableName + ShellScriptExtension; /// protected override string ByondRevisionsUrlTemplate => "https://www.byond.com/download/build/{0}/{0}.{1}_byond_linux.zip"; @@ -69,20 +69,10 @@ public PosixByondInstaller( "./byond/cache")); } - /// - public override string GetDreamDaemonName(ByondVersion version, out bool supportsCli, out bool supportsMapThreads) - { - ArgumentNullException.ThrowIfNull(version); - - supportsCli = true; - supportsMapThreads = version.Version >= MapThreadsVersion; - return DreamDaemonExecutableName + ShellScriptExtension; - } - /// public override ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken) { - ArgumentNullException.ThrowIfNull(version); + CheckVersionValidity(version); ArgumentNullException.ThrowIfNull(path); // write the scripts for running the ting @@ -99,14 +89,14 @@ async ValueTask WriteAndMakeExecutable(string pathToScript, string script) postWriteHandler.HandleWrite(IOManager.ResolvePath(pathToScript)); } - var basePath = IOManager.ConcatPath(path, EngineManager.BinPath); + var basePath = IOManager.ConcatPath(path, BinPath); var ddTask = WriteAndMakeExecutable( - IOManager.ConcatPath(basePath, GetDreamDaemonName(version, out _, out _)), + IOManager.ConcatPath(basePath, GetDreamDaemonName(version.Version, out _)), dreamDaemonScript); var dmTask = WriteAndMakeExecutable( - IOManager.ConcatPath(basePath, CompilerName), + IOManager.ConcatPath(basePath, DreamMakerName), dreamMakerScript); var task = ValueTaskExtensions.WhenAll( @@ -122,10 +112,17 @@ async ValueTask WriteAndMakeExecutable(string pathToScript, string script) /// public override ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken) { - ArgumentNullException.ThrowIfNull(version); + CheckVersionValidity(version); ArgumentNullException.ThrowIfNull(path); return ValueTask.CompletedTask; } + + /// + protected override string GetDreamDaemonName(Version byondVersion, out bool supportsCli) + { + supportsCli = true; + return DreamDaemonExecutableName + ShellScriptExtension; + } } } diff --git a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs index da9105d5b5c..d9a9d02cb4d 100644 --- a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs @@ -54,10 +54,10 @@ sealed class WindowsByondInstaller : ByondInstallerBase, IDisposable public static Version DDExeVersion => new (515, 1598); /// - public override string CompilerName => "dm.exe"; + protected override string DreamMakerName => "dm.exe"; /// - public override string PathToUserFolder { get; } + protected override string PathToUserFolder { get; } /// protected override string ByondRevisionsUrlTemplate => "https://www.byond.com/download/build/{0}/{0}.{1}_byond.zip"; @@ -114,19 +114,12 @@ public WindowsByondInstaller( /// public void Dispose() => semaphore.Dispose(); - /// - public override string GetDreamDaemonName(ByondVersion version, out bool supportsCli, out bool supportsMapThreads) - { - ArgumentNullException.ThrowIfNull(version); - - supportsCli = version.Version >= DDExeVersion; - supportsMapThreads = version.Version >= MapThreadsVersion; - return supportsCli ? "dd.exe" : "dreamdaemon.exe"; - } - /// public override ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken) { + CheckVersionValidity(version); + ArgumentNullException.ThrowIfNull(path); + var tasks = new List(3) { SetNoPromptTrusted(path, cancellationToken), @@ -134,7 +127,7 @@ public override ValueTask Install(ByondVersion version, string path, Cancellatio }; if (!generalConfiguration.SkipAddingByondFirewallException) - tasks.Add(AddDreamDaemonToFirewall(version, path, cancellationToken)); + tasks.Add(AddDreamDaemonToFirewall(version.Version, path, cancellationToken)); return ValueTaskExtensions.WhenAll(tasks); } @@ -142,7 +135,7 @@ public override ValueTask Install(ByondVersion version, string path, Cancellatio /// public override async ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken) { - ArgumentNullException.ThrowIfNull(version); + CheckVersionValidity(version); ArgumentNullException.ThrowIfNull(path); if (generalConfiguration.SkipAddingByondFirewallException) @@ -155,7 +148,14 @@ public override async ValueTask UpgradeInstallation(ByondVersion version, string return; Logger.LogInformation("BYOND Version {version} needs dd.exe added to firewall", version); - await AddDreamDaemonToFirewall(version, path, cancellationToken); + await AddDreamDaemonToFirewall(version.Version, path, cancellationToken); + } + + /// + protected override string GetDreamDaemonName(Version byondVersion, out bool supportsCli) + { + supportsCli = byondVersion >= DDExeVersion; + return supportsCli ? "dd.exe" : "dreamdaemon.exe"; } /// @@ -224,18 +224,18 @@ async ValueTask InstallDirectX(string path, CancellationToken cancellationToken) /// /// Attempt to add the DreamDaemon executable as an exception to the Windows firewall. /// - /// The BYOND . + /// The BYOND . /// The path to the BYOND installation. /// The for the operation. /// A representing the running operation. - async ValueTask AddDreamDaemonToFirewall(ByondVersion version, string path, CancellationToken cancellationToken) + async ValueTask AddDreamDaemonToFirewall(Version byondVersion, string path, CancellationToken cancellationToken) { - var dreamDaemonName = GetDreamDaemonName(version, out var usesDDExe, out var _); + var dreamDaemonName = GetDreamDaemonName(byondVersion, out var usesDDExe); var dreamDaemonPath = IOManager.ResolvePath( IOManager.ConcatPath( path, - EngineManager.BinPath, + BinPath, dreamDaemonName)); Logger.LogInformation("Adding Windows Firewall exception for {path}...", dreamDaemonPath); @@ -244,7 +244,7 @@ async ValueTask AddDreamDaemonToFirewall(ByondVersion version, string path, Canc // I really wish we could add the instance name here but // 1. It'd make IByondInstaller need to be transient per-instance and WindowsByondInstaller relys on being a singleton for its DX installer call // 2. The instance could be renamed, so it'd have to be an unfriendly ID anyway. - var arguments = $"advfirewall firewall add rule name=\"TGS DreamDaemon {version}\" program=\"{dreamDaemonPath}\" protocol=tcp dir=in enable=yes action=allow"; + var arguments = $"advfirewall firewall add rule name=\"TGS DreamDaemon {byondVersion}\" program=\"{dreamDaemonPath}\" protocol=tcp dir=in enable=yes action=allow"; await using var netshProcess = processExecutor.LaunchProcess( "netsh.exe", IOManager.ResolvePath(), diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index 0533ee0270b..5414e0115c0 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -73,7 +73,7 @@ sealed class InstanceFactory : IInstanceFactory /// /// The for the . /// - readonly IEngineInstaller byondInstaller; + readonly IEngineInstaller engineInstaller; /// /// The for the . @@ -174,7 +174,7 @@ sealed class InstanceFactory : IInstanceFactory /// The value of . /// The value of . /// The value of . - /// The value of . + /// The value of . /// The value of . /// The value of . /// The value of . @@ -200,7 +200,7 @@ public InstanceFactory( ICryptographySuite cryptographySuite, ISynchronousIOManager synchronousIOManager, ISymlinkFactory symlinkFactory, - IEngineInstaller byondInstaller, + IEngineInstaller engineInstaller, IChatManagerFactory chatFactory, IProcessExecutor processExecutor, IPostWriteHandler postWriteHandler, @@ -226,7 +226,7 @@ public InstanceFactory( this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite)); this.synchronousIOManager = synchronousIOManager ?? throw new ArgumentNullException(nameof(synchronousIOManager)); this.symlinkFactory = symlinkFactory ?? throw new ArgumentNullException(nameof(symlinkFactory)); - this.byondInstaller = byondInstaller ?? throw new ArgumentNullException(nameof(byondInstaller)); + this.engineInstaller = engineInstaller ?? throw new ArgumentNullException(nameof(engineInstaller)); this.chatFactory = chatFactory ?? throw new ArgumentNullException(nameof(chatFactory)); this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); this.postWriteHandler = postWriteHandler ?? throw new ArgumentNullException(nameof(postWriteHandler)); @@ -296,7 +296,7 @@ public async ValueTask CreateInstance(IBridgeRegistrar bridgeRegistra generalConfiguration); try { - var byond = new EngineManager(byondIOManager, byondInstaller, eventConsumer, loggerFactory.CreateLogger()); + var byond = new EngineManager(byondIOManager, engineInstaller, eventConsumer, loggerFactory.CreateLogger()); var dmbFactory = new DmbFactory( databaseContextFactory, @@ -419,7 +419,7 @@ public async ValueTask CreateInstance(IBridgeRegistrar bridgeRegistra public Task StartAsync(CancellationToken cancellationToken) { CheckSystemCompatibility(); - return byondInstaller.CleanCache(cancellationToken); + return engineInstaller.CleanCache(cancellationToken); } /// diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index 42732cf6ae0..260e69fe00e 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -139,26 +139,17 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode #pragma warning restore CA1506 #pragma warning restore CA1502 { + throw new NotImplementedException("Fix OD/BYOND model validation"); + ArgumentNullException.ThrowIfNull(model); var uploadingZip = model.UploadCustomZip == true; var isByondEngine = model.Engine.Value == EngineType.Byond; - if ((isByondEngine && (model.Version.Revision != -1 || (uploadingZip && model.Version.Build > 0) || model.SourceCommittish != null || model.SourceRepository != null)) + if ((isByondEngine && (model.Version.Revision != -1 || (uploadingZip && model.Version.Build > 0) || model.SourceCommittish != null)) || (!isByondEngine && (model.Version != null || String.IsNullOrWhiteSpace(model.SourceCommittish)))) return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); - Uri sourceRepo; - if (isByondEngine) - { - model.Version = NormalizeByondVersion(model.Version); - sourceRepo = null; - } - else - { - sourceRepo = model.SourceRepository ?? new Uri("https://github.com/OpenDreamProject/OpenDream"); - } - var userByondRights = AuthenticationContext.InstancePermissionSet.ByondRights.Value; if ((!userByondRights.HasFlag(ByondRights.InstallOfficialOrChangeActiveByondVersion) && !uploadingZip) || (!userByondRights.HasFlag(ByondRights.InstallCustomByondVersion) && uploadingZip)) @@ -230,12 +221,6 @@ await jobManager.RegisterOperation( job, async (core, databaseContextFactory, paramJob, progressHandler, jobCancellationToken) => { - if (sourceRepo != null) - await core.EngineManager.EnsureEngineSource( - sourceRepo, - model.Engine.Value, - jobCancellationToken); - MemoryStream zipFileStream = null; if (fileUploadTicket != null) await using (fileUploadTicket) diff --git a/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs b/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs index c210cb1b547..7429112712a 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs @@ -259,5 +259,23 @@ public Task GetPullRequest(string repoOwner, string repoName, int p pullRequestNumber) .WaitAsync(cancellationToken); } + + /// + public Task GetCommit(string repoOwner, string repoName, string committish, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(repoOwner); + + ArgumentNullException.ThrowIfNull(repoName); + + logger.LogTrace("GetPulGetCommitlRequest"); + return gitHubClient + .Repository + .Commit + .Get( + repoOwner, + repoName, + committish) + .WaitAsync(cancellationToken); + } } } diff --git a/src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs b/src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs index 2bc7e9c2d31..e2f338d77aa 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs @@ -63,5 +63,15 @@ public interface IGitHubService /// The for the operation. /// A resulting in the target . Task GetPullRequest(string repoOwner, string repoName, int pullRequestNumber, CancellationToken cancellationToken); + + /// + /// Get a given . + /// + /// The owner of the target repository. + /// The name of the target repository. + /// The target SHA or ref to get the commit for. + /// The for the operation. + /// A resulting in the target . + Task GetCommit(string repoOwner, string repoName, string committish, CancellationToken cancellationToken); } } diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 2268852074c..317bf216805 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -146,6 +146,8 @@ await byondInstaller.DownloadVersion( Assert.IsFalse(hasEntry); } + static Version MapThreadsVersion() => (Version)typeof(ByondInstallerBase).GetField("MapThreadsVersion", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) ?? throw new InvalidOperationException("Couldn't find MapThreadsVersion"); + [TestMethod] public async Task TestMapThreadsByondVersion() { @@ -167,19 +169,19 @@ public async Task TestMapThreadsByondVersion() var logger = loggerFactory.CreateLogger(); var init1 = CachingFileDownloader.InitializeByondVersion( logger, - ByondInstallerBase.MapThreadsVersion, + MapThreadsVersion(), platformIdentifier.IsWindows, CancellationToken.None); await CachingFileDownloader.InitializeByondVersion( logger, - new Version(ByondInstallerBase.MapThreadsVersion.Major, ByondInstallerBase.MapThreadsVersion.Minor - 1), + new Version(MapThreadsVersion().Major, MapThreadsVersion().Minor - 1), platformIdentifier.IsWindows, CancellationToken.None); await init1; var fileDownloader = new CachingFileDownloader(Mock.Of>()); - IEngineInstaller byondInstaller = platformIdentifier.IsWindows + ByondInstallerBase byondInstaller = platformIdentifier.IsWindows ? new WindowsByondInstaller( Mock.Of(), Mock.Of(), @@ -214,13 +216,13 @@ await TestMapThreadsVersion( new ByondVersion { Engine = EngineType.Byond, - Version = ByondInstallerBase.MapThreadsVersion, + Version = MapThreadsVersion(), }, await byondInstaller.DownloadVersion( new ByondVersion { Engine = EngineType.Byond, - Version = ByondInstallerBase.MapThreadsVersion + Version = MapThreadsVersion() }, default), byondInstaller, @@ -230,7 +232,7 @@ await byondInstaller.DownloadVersion( await ioManager.DeleteDirectory(tempPath, default); - var (byondBytes, version) = await GetByondVersionPriorTo(byondInstaller, ByondInstallerBase.MapThreadsVersion); + var (byondBytes, version) = await GetByondVersionPriorTo(byondInstaller, MapThreadsVersion()); await TestMapThreadsVersion( version, @@ -425,7 +427,7 @@ static async Task> GetByondVersionPriorTo(IEng static async Task TestMapThreadsVersion( ByondVersion byondVersion, Stream byondBytes, - IEngineInstaller byondInstaller, + ByondInstallerBase byondInstaller, IIOManager ioManager, IProcessExecutor processExecutor, string tempPath) @@ -434,17 +436,26 @@ static async Task TestMapThreadsVersion( await ioManager.ZipToDirectory(tempPath, byondBytes, default); // HAAAAAAAX - if (byondInstaller.GetType() == typeof(WindowsByondInstaller)) + var installerType = byondInstaller.GetType(); + if (byondInstaller is WindowsByondInstaller) typeof(WindowsByondInstaller).GetField("installedDirectX", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(byondInstaller, true); await byondInstaller.Install(byondVersion, tempPath, default); + var binPath = (string)typeof(ByondInstallerBase).GetField("BinPath", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); + var ddNameFunc = installerType.GetMethod("GetDreamDaemonName", BindingFlags.Instance | BindingFlags.NonPublic); + var supportsCli = false; + var argArray = new object[] { byondVersion.Version, supportsCli }; + + // https://stackoverflow.com/questions/2438065/how-can-i-invoke-a-method-with-an-out-parameter var ddPath = ioManager.ConcatPath( tempPath, - EngineManager.BinPath, - byondInstaller.GetDreamDaemonName(byondVersion, out var supportsCli, out var shouldSupportMapThreads)); + binPath, + (string)ddNameFunc.Invoke(byondInstaller, argArray)); + + Assert.IsTrue((bool)argArray[1]); - Assert.IsTrue(supportsCli); + var shouldSupportMapThreads = byondVersion.Version >= MapThreadsVersion(); await File.WriteAllBytesAsync("fake.dmb", Array.Empty(), CancellationToken.None); From b93b9bf6b952841205be61626d739c3317cb84d0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 10 Oct 2023 08:45:05 -0400 Subject: [PATCH 033/717] Rename Byond namespace to Engine --- .../Components/Chat/Commands/ByondCommand.cs | 2 +- .../Components/Chat/Commands/CommandFactory.cs | 2 +- .../Components/Deployment/DreamMaker.cs | 2 +- .../{Byond => Engine}/ByondInstallation.cs | 2 +- .../{Byond => Engine}/ByondInstallerBase.cs | 2 +- .../{Byond => Engine}/EngineExecutableLock.cs | 2 +- .../{Byond => Engine}/EngineInstallerBase.cs | 2 +- .../Components/{Byond => Engine}/EngineManager.cs | 2 +- .../{Byond => Engine}/IEngineExecutableLock.cs | 2 +- .../{Byond => Engine}/IEngineInstallation.cs | 2 +- .../{Byond => Engine}/IEngineInstaller.cs | 2 +- .../Components/{Byond => Engine}/IEngineManager.cs | 2 +- .../{Byond => Engine}/OpenDreamInstallation.cs | 2 +- .../{Byond => Engine}/OpenDreamInstaller.cs | 3 +-- .../{Byond => Engine}/PosixByondInstaller.cs | 2 +- .../{Byond => Engine}/WindowsByondInstaller.cs | 2 +- .../Components/IInstanceCore.cs | 2 +- src/Tgstation.Server.Host/Components/Instance.cs | 2 +- .../Components/InstanceFactory.cs | 2 +- .../Components/InstanceWrapper.cs | 2 +- .../Session/ISessionControllerFactory.cs | 2 +- .../Components/Session/SessionController.cs | 14 +++++++------- .../Components/Session/SessionControllerFactory.cs | 2 +- .../Controllers/ByondController.cs | 1 - src/Tgstation.Server.Host/Core/Application.cs | 2 +- .../{Byond => Engine}/TestPosixByondInstaller.cs | 2 +- .../Live/DummyChatProviderFactory.cs | 2 +- .../Live/DummyGitHubService.cs | 13 +++++++++++++ .../Live/Instance/ByondTest.cs | 5 +---- .../Live/Instance/InstanceTest.cs | 2 +- tests/Tgstation.Server.Tests/TestVersions.cs | 2 +- 31 files changed, 48 insertions(+), 40 deletions(-) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/ByondInstallation.cs (99%) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/ByondInstallerBase.cs (99%) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/EngineExecutableLock.cs (96%) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/EngineInstallerBase.cs (98%) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/EngineManager.cs (99%) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/IEngineExecutableLock.cs (87%) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/IEngineInstallation.cs (97%) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/IEngineInstaller.cs (98%) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/IEngineManager.cs (98%) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/OpenDreamInstallation.cs (97%) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/OpenDreamInstaller.cs (98%) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/PosixByondInstaller.cs (98%) rename src/Tgstation.Server.Host/Components/{Byond => Engine}/WindowsByondInstaller.cs (99%) rename tests/Tgstation.Server.Host.Tests/Components/{Byond => Engine}/TestPosixByondInstaller.cs (98%) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs index 9cfc07fbd78..29a9335be46 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; using Tgstation.Server.Api.Models; -using Tgstation.Server.Host.Components.Byond; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Watchdog; diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs index d8678fe85ff..cb75153b741 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Components.Watchdog; using Tgstation.Server.Host.Database; diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index c9ea5a5c727..6a5f5242253 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -11,9 +11,9 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; -using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment.Remote; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Components.Session; diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs similarity index 99% rename from src/Tgstation.Server.Host/Components/Byond/ByondInstallation.cs rename to src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs index 35a7fd614f8..81156de45bd 100644 --- a/src/Tgstation.Server.Host/Components/Byond/ByondInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs @@ -9,7 +9,7 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// /// Implementation of for . diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs similarity index 99% rename from src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs rename to src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index 7c094041bcb..f3659e3097a 100644 --- a/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -11,7 +11,7 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Utils; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// /// Base implementation of for . diff --git a/src/Tgstation.Server.Host/Components/Byond/EngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs similarity index 96% rename from src/Tgstation.Server.Host/Components/Byond/EngineExecutableLock.cs rename to src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs index 9c3d2ebdfcf..3fd50f4c853 100644 --- a/src/Tgstation.Server.Host/Components/Byond/EngineExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs @@ -5,7 +5,7 @@ using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Utils; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// sealed class EngineExecutableLock : ReferenceCounter, IEngineExecutableLock diff --git a/src/Tgstation.Server.Host/Components/Byond/EngineInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs similarity index 98% rename from src/Tgstation.Server.Host/Components/Byond/EngineInstallerBase.cs rename to src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs index eef9da9ea78..94e0ffd1a9e 100644 --- a/src/Tgstation.Server.Host/Components/Byond/EngineInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs @@ -9,7 +9,7 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// abstract class EngineInstallerBase : IEngineInstaller diff --git a/src/Tgstation.Server.Host/Components/Byond/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs similarity index 99% rename from src/Tgstation.Server.Host/Components/Byond/EngineManager.cs rename to src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index b60610d1175..b4594ef7b38 100644 --- a/src/Tgstation.Server.Host/Components/Byond/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -17,7 +17,7 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// sealed class EngineManager : IEngineManager diff --git a/src/Tgstation.Server.Host/Components/Byond/IEngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineExecutableLock.cs similarity index 87% rename from src/Tgstation.Server.Host/Components/Byond/IEngineExecutableLock.cs rename to src/Tgstation.Server.Host/Components/Engine/IEngineExecutableLock.cs index ae3ad5d4383..66031902fbb 100644 --- a/src/Tgstation.Server.Host/Components/Byond/IEngineExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineExecutableLock.cs @@ -1,6 +1,6 @@ using System; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// /// Represents usage of the two primary BYOND server executables. diff --git a/src/Tgstation.Server.Host/Components/Byond/IEngineInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs similarity index 97% rename from src/Tgstation.Server.Host/Components/Byond/IEngineInstallation.cs rename to src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs index 39c29b547a3..75ebbab4c87 100644 --- a/src/Tgstation.Server.Host/Components/Byond/IEngineInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs @@ -4,7 +4,7 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// /// Represents a BYOND installation. diff --git a/src/Tgstation.Server.Host/Components/Byond/IEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs similarity index 98% rename from src/Tgstation.Server.Host/Components/Byond/IEngineInstaller.cs rename to src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs index 9f389e84747..d4ba08d916e 100644 --- a/src/Tgstation.Server.Host/Components/Byond/IEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs @@ -4,7 +4,7 @@ using Tgstation.Server.Api.Models.Internal; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// /// For downloading and installing game engines for a given system. diff --git a/src/Tgstation.Server.Host/Components/Byond/IEngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs similarity index 98% rename from src/Tgstation.Server.Host/Components/Byond/IEngineManager.cs rename to src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs index a336b1f5077..1951fbc4bc9 100644 --- a/src/Tgstation.Server.Host/Components/Byond/IEngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs @@ -8,7 +8,7 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Jobs; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// /// For managing the engine installations. diff --git a/src/Tgstation.Server.Host/Components/Byond/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs similarity index 97% rename from src/Tgstation.Server.Host/Components/Byond/OpenDreamInstallation.cs rename to src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index a7df3ddc286..cdff39ed41c 100644 --- a/src/Tgstation.Server.Host/Components/Byond/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -6,7 +6,7 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// /// Implementation of for . diff --git a/src/Tgstation.Server.Host/Components/Byond/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs similarity index 98% rename from src/Tgstation.Server.Host/Components/Byond/OpenDreamInstaller.cs rename to src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 53786bfb6a8..f12ba859d34 100644 --- a/src/Tgstation.Server.Host/Components/Byond/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -13,7 +13,7 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils.GitHub; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// /// Implementation of for . @@ -115,7 +115,6 @@ public override ValueTask TrustDmbPath(string fullDmbPath, CancellationToken can protected override async ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken) { throw new NotImplementedException("This won't work because of the goddamn fucking robust toolbox submodule"); - var fullCommit = await gitHubService.GetCommit("OpenDreamProject", "OpenDream", version.SourceCommittish, cancellationToken); if (fullCommit.Sha != version.SourceCommittish) diff --git a/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs similarity index 98% rename from src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs rename to src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs index b9015eddd8f..06831bb98fa 100644 --- a/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs @@ -10,7 +10,7 @@ using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.IO; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// /// for Posix systems. diff --git a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs similarity index 99% rename from src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs rename to src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index d9a9d02cb4d..1d9336af8f1 100644 --- a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -16,7 +16,7 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -namespace Tgstation.Server.Host.Components.Byond +namespace Tgstation.Server.Host.Components.Engine { /// /// for windows systems. diff --git a/src/Tgstation.Server.Host/Components/IInstanceCore.cs b/src/Tgstation.Server.Host/Components/IInstanceCore.cs index c19dffad829..78bce9e3f31 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceCore.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceCore.cs @@ -1,8 +1,8 @@ using System.Threading.Tasks; -using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Components.StaticFiles; using Tgstation.Server.Host.Components.Watchdog; diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 6d9c61e118b..acd7933f10b 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -9,10 +9,10 @@ using Serilog.Context; using Tgstation.Server.Api.Rights; -using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Components.Deployment.Remote; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Components.Watchdog; diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index 5414e0115c0..0199f1de087 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -5,11 +5,11 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Chat.Commands; using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Components.Deployment.Remote; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.Components.Repository; diff --git a/src/Tgstation.Server.Host/Components/InstanceWrapper.cs b/src/Tgstation.Server.Host/Components/InstanceWrapper.cs index 08e2792e01e..55f5ea76988 100644 --- a/src/Tgstation.Server.Host/Components/InstanceWrapper.cs +++ b/src/Tgstation.Server.Host/Components/InstanceWrapper.cs @@ -2,9 +2,9 @@ using System.Threading; using System.Threading.Tasks; -using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Components.StaticFiles; using Tgstation.Server.Host.Components.Watchdog; diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs index 4ece5faa3e2..26cc5e4a634 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs @@ -2,8 +2,8 @@ using System.Threading.Tasks; using Tgstation.Server.Api.Models.Internal; -using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.Components.Engine; namespace Tgstation.Server.Host.Components.Session { diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 13e6d0705a6..f8a9a928f90 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -15,9 +15,9 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Common.Extensions; -using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.Components.Interop.Topic; @@ -108,9 +108,9 @@ async Task Wrap() public ReattachInformation ReattachInformation { get; } /// - /// The for the . + /// The for the . /// - readonly global::Byond.TopicSender.ITopicClient byondTopicSender; + readonly Byond.TopicSender.ITopicClient byondTopicSender; /// /// The for the . @@ -245,7 +245,7 @@ public SessionController( Api.Models.Instance metadata, IProcess process, IEngineExecutableLock byondLock, - global::Byond.TopicSender.ITopicClient byondTopicSender, + Byond.TopicSender.ITopicClient byondTopicSender, IChatTrackingContext chatTrackingContext, IBridgeRegistrar bridgeRegistrar, IChatManager chat, @@ -949,11 +949,11 @@ bool LogRequestIssue(bool possiblyFromCompletedRequest) } /// - /// Generates a query string for a given set of . + /// Generates a query string for a given set of . /// /// The to serialize. /// The intermediate JSON prior to URL encoding. - /// The query string for the given . + /// The query string for the given . string GenerateQueryString(TopicParameters parameters, out string json) { json = JsonConvert.SerializeObject(parameters, DMApiConstants.SerializerSettings); @@ -983,7 +983,7 @@ async ValueTask SendRawTopic(string queryString, bool pri var targetPort = ReattachInformation.Port; var killedOrRebootedTask = Task.WhenAny(Lifetime, OnReboot); - global::Byond.TopicSender.TopicResponse byondResponse = null; + Byond.TopicSender.TopicResponse byondResponse = null; var firstSend = true; using (await topicSendSemaphore.Lock(cancellationToken)) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 5a72ee8c015..3bd4744a649 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -11,9 +11,9 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; -using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Interop.Bridge; diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index 260e69fe00e..34ab4684319 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -140,7 +140,6 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode #pragma warning restore CA1502 { throw new NotImplementedException("Fix OD/BYOND model validation"); - ArgumentNullException.ThrowIfNull(model); var uploadingZip = model.UploadCustomZip == true; diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 6cee39ad160..eaeeb9a9541 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -29,9 +29,9 @@ using Tgstation.Server.Api; using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Components; -using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment.Remote; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.Components.Repository; diff --git a/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs similarity index 98% rename from tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs rename to tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs index 8ce2d11787d..e17ac8a4906 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs @@ -10,7 +10,7 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; -namespace Tgstation.Server.Host.Components.Byond.Tests +namespace Tgstation.Server.Host.Components.Engine.Tests { [TestClass] public sealed class TestPosixByondInstaller diff --git a/tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs b/tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs index ba12c498ec5..dec859f6afb 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs @@ -6,7 +6,7 @@ using Moq; using Tgstation.Server.Api.Models; -using Tgstation.Server.Host.Components.Byond; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Chat.Commands; using Tgstation.Server.Host.Components.Chat.Providers; using Tgstation.Server.Host.Components.Deployment; diff --git a/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs b/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs index 709b312bbfc..1b2e711ba68 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs @@ -23,6 +23,7 @@ sealed class DummyGitHubService : IAuthenticatedGitHubService { static Dictionary releasesDictionary; static PullRequest testPr; + static GitHubCommit testCommit; readonly ICryptographySuite cryptographySuite; readonly ILogger logger; @@ -56,10 +57,16 @@ public static async Task InitializeAndInject(CancellationToken cancellationToken { TestLiveServer.TestUpdateVersion, targetRelease } }; + var testCommitTask = gitHubClient + .Repository + .Commit + .Get("Cyberboss", "common_core", "4b4926dfaf6295f19f8ae7abf03cb357dbb05b29") + .WaitAsync(cancellationToken); testPr = await gitHubClient .PullRequest .Get("Cyberboss", "common_core", 2) .WaitAsync(cancellationToken); + testCommit = await testCommitTask; ServiceCollectionExtensions.UseGitHubServiceFactory(); } @@ -125,6 +132,12 @@ public Task GetPullRequest(string repoOwner, string repoName, int p return Task.FromResult(testPr); } + public Task GetCommit(string repoOwner, string repoName, string committish, CancellationToken cancellationToken) + { + logger.LogTrace("GetPullRequest"); + return Task.FromResult(testCommit); + } + public ValueTask> GetTgsReleases(CancellationToken cancellationToken) { logger.LogTrace("GetTgsReleases"); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index 3010f92e880..16e059e70ee 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -6,11 +6,8 @@ using System.Threading; using System.Threading.Tasks; -using Elasticsearch.Net.Specification.IndexLifecycleManagementApi; - using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.VisualStudio.TestPlatform.CrossPlatEngine; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -22,7 +19,7 @@ using Tgstation.Server.Client; using Tgstation.Server.Client.Components; using Tgstation.Server.Common.Extensions; -using Tgstation.Server.Host.Components.Byond; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 22dc9edec89..0ab2cb1acf5 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -16,7 +16,7 @@ using Tgstation.Server.Client; using Tgstation.Server.Client.Components; using Tgstation.Server.Host.Components; -using Tgstation.Server.Host.Components.Byond; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 317bf216805..06cce64ee77 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -21,7 +21,7 @@ using Tgstation.Server.Client; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host; -using Tgstation.Server.Host.Components.Byond; +using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Database; From 98e840461876fa4083d5fba09ee21b5722a0b805 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 11 Oct 2023 23:35:07 -0400 Subject: [PATCH 034/717] Make some repostory progress reporters optional Also, report checkout progress --- .../Components/Repository/IRepository.cs | 4 +- .../Repository/IRepositoryManager.cs | 2 +- .../Components/Repository/Repository.cs | 63 +++++++++++-------- .../Repository/RepositoryManager.cs | 19 +++++- 4 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepository.cs b/src/Tgstation.Server.Host/Components/Repository/IRepository.cs index 5cce4208ea2..33c4b9a97c0 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IRepository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IRepository.cs @@ -47,7 +47,7 @@ public interface IRepository : IGitRemoteAdditionalInformation, IDisposable /// The username used for fetching from submodule repositories. /// The password used for fetching from submodule repositories. /// If a submodule update should be attempted after the merge. - /// The to report progress of the operation. + /// The optional to report progress of the operation. /// The for the operation. /// A representing the running operation. ValueTask CheckoutObject( @@ -83,7 +83,7 @@ ValueTask AddTestMerge( /// /// Fetch commits from the origin repository. /// - /// The to report progress of the operation. + /// The optional to report progress of the operation. /// The username to fetch from the origin repository. /// The password to fetch from the origin repository. /// If any events created should be marked as part of the deployment pipeline. diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs index f7c4a546083..d602730e151 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs @@ -35,7 +35,7 @@ public interface IRepositoryManager : IDisposable /// The branch to clone. /// The username to clone from . /// The password to clone from . - /// The for progress of the clone. + /// The optional for progress of the clone. /// If submodules should be recusively cloned and initialized. /// The for the operation. /// A resulting i the newly cloned , if one already exists. diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs index 46cc06fd8e5..5f3602675e2 100644 --- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs @@ -395,7 +395,7 @@ public async ValueTask CheckoutObject( CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(committish); - ArgumentNullException.ThrowIfNull(progressReporter); + logger.LogDebug("Checkout object: {committish}...", committish); await eventConsumer.HandleEvent(EventType.RepoCheckout, new List { committish }, false, cancellationToken); await Task.Factory.StartNew( @@ -404,7 +404,7 @@ await Task.Factory.StartNew( libGitRepo.RemoveUntrackedFiles(); RawCheckout( committish, - progressReporter.CreateSection(null, updateSubmodules ? 2.0 / 3 : 1.0), + progressReporter?.CreateSection(null, updateSubmodules ? 2.0 / 3 : 1.0), cancellationToken); }, cancellationToken, @@ -413,7 +413,7 @@ await Task.Factory.StartNew( if (updateSubmodules) await UpdateSubmodules( - progressReporter.CreateSection(null, 1.0 / 3), + progressReporter?.CreateSection(null, 1.0 / 3), username, password, false, @@ -428,7 +428,6 @@ public async ValueTask FetchOrigin( bool deploymentPipeline, CancellationToken cancellationToken) { - ArgumentNullException.ThrowIfNull(progressReporter); logger.LogDebug("Fetch origin..."); await eventConsumer.HandleEvent(EventType.RepoFetch, Enumerable.Empty(), deploymentPipeline, cancellationToken); await Task.Factory.StartNew( @@ -437,20 +436,24 @@ await Task.Factory.StartNew( var remote = libGitRepo.Network.Remotes.First(); try { + var fetchOptions = new FetchOptions + { + Prune = true, + OnProgress = (a) => !cancellationToken.IsCancellationRequested, + OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested, + CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password), + }; + + if (progressReporter != null) + fetchOptions.OnTransferProgress = TransferProgressHandler(progressReporter.CreateSection("Fetch Origin", 1.0), cancellationToken); + commands.Fetch( libGitRepo, remote .FetchRefSpecs .Select(x => x.Specification), remote, - new FetchOptions - { - Prune = true, - OnProgress = (a) => !cancellationToken.IsCancellationRequested, - OnTransferProgress = TransferProgressHandler(progressReporter.CreateSection("Fetch Origin", 1.0), cancellationToken), - OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested, - CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password), - }, + fetchOptions, "Fetch origin commits"); } catch (UserCancelledException) @@ -855,23 +858,27 @@ public Task TimestampCommit(string sha, CancellationToken cancel /// Runs a blocking force checkout to . /// /// The committish to checkout. - /// The for the operation. + /// The optional for the operation. /// The for the operation. void RawCheckout(string committish, JobProgressReporter progressReporter, CancellationToken cancellationToken) { logger.LogTrace("Checkout: {committish}", committish); - var stage = $"Checkout {committish}"; - progressReporter = progressReporter.CreateSection(stage, 1.0); - progressReporter.ReportProgress(0); - cancellationToken.ThrowIfCancellationRequested(); - var checkoutOptions = new CheckoutOptions { CheckoutModifiers = CheckoutModifiers.Force, - OnCheckoutProgress = CheckoutProgressHandler(progressReporter), }; + if (progressReporter != null) + { + var stage = $"Checkout {committish}"; + progressReporter = progressReporter.CreateSection(stage, 1.0); + progressReporter.ReportProgress(0); + checkoutOptions.OnCheckoutProgress = CheckoutProgressHandler(progressReporter); + } + + cancellationToken.ThrowIfCancellationRequested(); + void RunCheckout() => commands.Checkout( libGitRepo, checkoutOptions, @@ -987,7 +994,7 @@ PushOptions GeneratePushOptions(JobProgressReporter progressReporter, string use /// /// Recusively update all s in the . /// - /// of the operation. + /// Optional of the operation. /// The username for the . /// The password for the . /// If any events created should be marked as part of the deployment pipeline. @@ -1015,16 +1022,20 @@ async ValueTask UpdateSubmodules( var submoduleUpdateOptions = new SubmoduleUpdateOptions { Init = true, - OnTransferProgress = TransferProgressHandler( - progressReporter.CreateSection($"Fetch submodule {submodule.Name}", factor), - cancellationToken), OnProgress = output => !cancellationToken.IsCancellationRequested, OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested, CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password), - OnCheckoutProgress = CheckoutProgressHandler( - progressReporter.CreateSection($"Checkout submodule {submodule.Name}", factor)), }; + if (progressReporter != null) + { + submoduleUpdateOptions.OnTransferProgress = TransferProgressHandler( + progressReporter.CreateSection($"Fetch submodule {submodule.Name}", factor), + cancellationToken); + submoduleUpdateOptions.OnCheckoutProgress = CheckoutProgressHandler( + progressReporter.CreateSection($"Checkout submodule {submodule.Name}", factor)); + } + logger.LogDebug("Updating submodule {submoduleName}...", submodule.Name); Task RawSubModuleUpdate() => Task.Factory.StartNew( () => libGitRepo.Submodules.Update(submodule.Name, submoduleUpdateOptions), @@ -1039,7 +1050,7 @@ Task RawSubModuleUpdate() => Task.Factory.StartNew( { // workaround for https://github.com/libgit2/libgit2/issues/3820 // kill off the modules/ folder in .git and try again - progressReporter.ReportProgress(null); + progressReporter?.ReportProgress(null); credentialsProvider.CheckBadCredentialsException(ex); logger.LogWarning(ex, "Initial update of submodule {submoduleName} failed. Deleting submodule directories and re-attempting...", submodule.Name); diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs index 61b6e609b03..2940e0d1349 100644 --- a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs +++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs @@ -127,7 +127,6 @@ public async ValueTask CloneRepository( CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(url); - ArgumentNullException.ThrowIfNull(progressReporter); logger.LogInformation("Begin clone {url} (Branch: {initialBranch})", url, initialBranch); lock (semaphore) @@ -146,18 +145,32 @@ public async ValueTask CloneRepository( if (!await ioManager.DirectoryExists(repositoryPath, cancellationToken)) try { + var cloneProgressReporter = progressReporter?.CreateSection(null, 0.75f); + var checkoutProgressReporter = progressReporter?.CreateSection(null, 0.25f); var cloneOptions = new CloneOptions { OnProgress = (a) => !cancellationToken.IsCancellationRequested, OnTransferProgress = (a) => { - var percentage = ((double)a.IndexedObjects + a.ReceivedObjects) / (a.TotalObjects * 2); - progressReporter.ReportProgress(percentage); + if (cloneProgressReporter != null) + { + var percentage = ((double)a.IndexedObjects + a.ReceivedObjects) / (a.TotalObjects * 2); + cloneProgressReporter.ReportProgress(percentage); + } + return !cancellationToken.IsCancellationRequested; }, RecurseSubmodules = recurseSubmodules, OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested, RepositoryOperationStarting = (a) => !cancellationToken.IsCancellationRequested, + OnCheckoutProgress = (path, completed, remaining) => + { + if (checkoutProgressReporter == null) + return; + + var percentage = (double)completed / remaining; + checkoutProgressReporter.ReportProgress(percentage); + }, BranchName = initialBranch, CredentialsProvider = repositoryFactory.GenerateCredentialsHandler(username, password), }; From 90d516cfb96bdc3197b440a5f2aaa632262b6042 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 11 Oct 2023 23:35:52 -0400 Subject: [PATCH 035/717] More OpenDream engine implementation --- .../Components/Engine/ByondInstallerBase.cs | 50 ++++++- .../Components/Engine/EngineInstallerBase.cs | 32 +--- .../Components/Engine/EngineManager.cs | 20 ++- .../Engine/IEngineInstallationData.cs | 20 +++ .../Components/Engine/IEngineInstaller.cs | 11 +- .../Components/Engine/OpenDreamInstaller.cs | 139 ++++++++++++++---- .../Components/Engine/PosixByondInstaller.cs | 2 +- .../RepositoryEngineInstallationData.cs | 59 ++++++++ .../Engine/WindowsByondInstaller.cs | 2 +- .../Engine/ZipStreamEngineInstallationData.cs | 43 ++++++ .../Configuration/GeneralConfiguration.cs | 10 ++ .../Engine/TestPosixByondInstaller.cs | 12 +- .../Live/Instance/ByondTest.cs | 2 +- .../Live/Instance/InstanceTest.cs | 2 +- tests/Tgstation.Server.Tests/TestVersions.cs | 44 +++--- tests/Tgstation.Server.Tests/TestingUtils.cs | 11 +- 16 files changed, 353 insertions(+), 106 deletions(-) create mode 100644 src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs create mode 100644 src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs create mode 100644 src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index f3659e3097a..6f2b0854e63 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -9,6 +9,7 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.Components.Engine @@ -66,15 +67,21 @@ abstract class ByondInstallerBase : EngineInstallerBase /// protected abstract string ByondRevisionsUrlTemplate { get; } + /// + /// The for the . + /// + readonly IFileDownloader fileDownloader; + /// /// Initializes a new instance of the class. /// /// The for the . - /// The for the . /// The for the . - protected ByondInstallerBase(IIOManager ioManager, IFileDownloader fileDownloader, ILogger logger) - : base(ioManager, fileDownloader, logger) + /// The value of . + protected ByondInstallerBase(IIOManager ioManager, ILogger logger, IFileDownloader fileDownloader) + : base(ioManager, logger) { + this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); } /// @@ -184,11 +191,29 @@ public override async ValueTask TrustDmbPath(string fullDmbPath, CancellationTok } /// - protected override ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken) + public override async ValueTask DownloadVersion(ByondVersion version, JobProgressReporter progressReporter, CancellationToken cancellationToken) { CheckVersionValidity(version); - var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Version.Major, version.Version.Minor); - return ValueTask.FromResult(new Uri(url)); + + var url = await GetDownloadZipUrl(version, cancellationToken); + Logger.LogTrace("Downloading {engineType} version {version} from {url}...", TargetEngineType, version, url); + + await using var download = fileDownloader.DownloadFile(url, null); + await using var buffer = new BufferedFileStreamProvider( + await download.GetResult(cancellationToken)); + + var stream = await buffer.GetOwnedResult(cancellationToken); + try + { + return new ZipStreamEngineInstallationData( + IOManager, + stream); + } + catch + { + await stream.DisposeAsync(); + throw; + } } /// @@ -198,5 +223,18 @@ protected override ValueTask GetDownloadZipUrl(ByondVersion version, Cancel /// Whether or not the returned path supports being run as a command-line application. /// The file name of the DreamDaemon executable. protected abstract string GetDreamDaemonName(Version byondVersion, out bool supportsCli); + + /// + /// Create a pointing to the location of the download for a given . + /// + /// The to create a for. + /// The for the operation. + /// A resulting in a new pointing to the version download location. + ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken) + { + CheckVersionValidity(version); + var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Version.Major, version.Version.Minor); + return ValueTask.FromResult(new Uri(url)); + } } } diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs index 94e0ffd1a9e..002819ff6cd 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Threading; using System.Threading.Tasks; @@ -8,6 +7,7 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.Jobs; namespace Tgstation.Server.Host.Components.Engine { @@ -29,21 +29,14 @@ abstract class EngineInstallerBase : IEngineInstaller /// protected ILogger Logger { get; } - /// - /// The for the . - /// - readonly IFileDownloader fileDownloader; - /// /// Initializes a new instance of the class. /// /// The value of . - /// The value of . /// The value of . - protected EngineInstallerBase(IIOManager ioManager, IFileDownloader fileDownloader, ILogger logger) + protected EngineInstallerBase(IIOManager ioManager, ILogger logger) { IOManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); - this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); } @@ -60,30 +53,11 @@ protected EngineInstallerBase(IIOManager ioManager, IFileDownloader fileDownload public abstract ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken); /// - public async ValueTask DownloadVersion(ByondVersion version, CancellationToken cancellationToken) - { - CheckVersionValidity(version); - - var url = await GetDownloadZipUrl(version, cancellationToken); - Logger.LogTrace("Downloading {engineType} version {version} from {url}...", TargetEngineType, version, url); - - await using var download = fileDownloader.DownloadFile(url, null); - await using var buffer = new BufferedFileStreamProvider( - await download.GetResult(cancellationToken)); - return await buffer.GetOwnedResult(cancellationToken); - } + public abstract ValueTask DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken); /// public abstract ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken); - /// - /// Create a pointing to the location of the download for a given . - /// - /// The to create a for. - /// The for the operation. - /// A resulting in a new pointing to the version download location. - protected abstract ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken); - /// /// Check that a given is of type . /// diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index b4594ef7b38..dc1bb72577c 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -497,18 +497,24 @@ async ValueTask DirectoryCleanup() var directoryCleanupTask = DirectoryCleanup(); try { - Stream versionZipStream; + IEngineInstallationData engineInstallationData; if (customVersionStream == null) { if (progressReporter != null) progressReporter.StageName = "Downloading version"; - versionZipStream = await engineInstaller.DownloadVersion(version, cancellationToken); + engineInstallationData = await engineInstaller.DownloadVersion(version, progressReporter, cancellationToken); + + progressReporter.ReportProgress(null); } else - versionZipStream = customVersionStream; +#pragma warning disable CA2000 // Dispose objects before losing scope, false positive + engineInstallationData = new ZipStreamEngineInstallationData( + ioManager, + customVersionStream); +#pragma warning restore CA2000 // Dispose objects before losing scope - await using (versionZipStream) + await using (engineInstallationData) { if (progressReporter != null) progressReporter.StageName = "Cleaning target directory"; @@ -516,10 +522,10 @@ async ValueTask DirectoryCleanup() await directoryCleanupTask; if (progressReporter != null) - progressReporter.StageName = "Extracting zip"; + progressReporter.StageName = "Extracting data"; - logger.LogTrace("Extracting downloaded BYOND zip to {extractPath}...", installFullPath); - await ioManager.ZipToDirectory(installFullPath, versionZipStream, cancellationToken); + logger.LogTrace("Extracting engine to {extractPath}...", installFullPath); + await engineInstallationData.ExtractToPath(installFullPath, cancellationToken); } if (progressReporter != null) diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs new file mode 100644 index 00000000000..b3d8458973c --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs @@ -0,0 +1,20 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Tgstation.Server.Host.Components.Engine +{ + /// + /// Wraps data containing an engine installation. + /// + interface IEngineInstallationData : IAsyncDisposable + { + /// + /// Extracts the installation to a given path. + /// + /// The full path to extract to. + /// The for the operation. + /// A representing the running operation. + Task ExtractToPath(string path, CancellationToken cancellationToken); + } +} diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs index d4ba08d916e..346599843e3 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs @@ -1,8 +1,8 @@ -using System.IO; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Jobs; namespace Tgstation.Server.Host.Components.Engine { @@ -22,10 +22,11 @@ interface IEngineInstaller /// /// Download a given engine . /// - /// The of BYOND to download. + /// The of the engine to download. + /// The optional for the operation. /// The for the operation. - /// A resulting in a of the zipfile. - ValueTask DownloadVersion(ByondVersion version, CancellationToken cancellationToken); + /// A resulting in the for the download. + ValueTask DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken); /// /// Does actions necessary to get an extracted installation working. diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index f12ba859d34..976131743c7 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -4,14 +4,16 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Common; +using Tgstation.Server.Host.Components.Repository; +using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.System; -using Tgstation.Server.Host.Utils.GitHub; namespace Tgstation.Server.Host.Components.Engine { @@ -20,6 +22,11 @@ namespace Tgstation.Server.Host.Components.Engine /// sealed class OpenDreamInstaller : EngineInstallerBase { + /// + /// The name of the subdirectory used for the 's copy. + /// + private const string InstallationRepositorySubDirectory = "SourceRepo"; + /// protected override EngineType TargetEngineType => EngineType.OpenDream; @@ -29,36 +36,42 @@ sealed class OpenDreamInstaller : EngineInstallerBase readonly IPlatformIdentifier platformIdentifier; /// - /// The for the . + /// The for the . /// - readonly IGitHubService gitHubService; + readonly IProcessExecutor processExecutor; /// - /// The for the . + /// The for the OpenDream repository. /// - readonly IProcessExecutor processExecutor; + readonly IRepositoryManager repositoryManager; + + /// + /// The for the . + /// + readonly GeneralConfiguration generalConfiguration; /// /// Initializes a new instance of the class. /// /// The for the . - /// The for the . /// The for the . /// The value of . - /// The value of . /// The value of . + /// The value of . + /// The containing value of . public OpenDreamInstaller( IIOManager ioManager, - IFileDownloader fileDownloader, ILogger logger, IPlatformIdentifier platformIdentifier, - IGitHubService gitHubService, - IProcessExecutor processExecutor) - : base(ioManager, fileDownloader, logger) + IProcessExecutor processExecutor, + IRepositoryManager repositoryManager, + IOptions generalConfigurationOptions) + : base(ioManager, logger) { this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); - this.gitHubService = gitHubService ?? throw new ArgumentNullException(nameof(gitHubService)); this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); + this.repositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager)); + generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } /// @@ -72,10 +85,63 @@ public override IEngineInstallation CreateInstallation(ByondVersion version, Tas } /// - public override async ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken) + public override async ValueTask DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken) { CheckVersionValidity(version); - ArgumentNullException.ThrowIfNull(path); + + // get a lock on a system wide OD repo + Logger.LogTrace("Cloning OD repo..."); + + var progressSection1 = jobProgressReporter.CreateSection("Updating OpenDream git repository", 0.5f); + + var repo = await repositoryManager.CloneRepository( + generalConfiguration.OpenDreamGitUrl, + null, + null, + null, + progressSection1, + true, + cancellationToken); + + try + { + if (repo == null) + { + Logger.LogTrace("OD repo seems to already exist, attempting load and fetch..."); + repo = await repositoryManager.LoadRepository(cancellationToken); + + await repo.FetchOrigin( + progressSection1, + null, + null, + false, + cancellationToken); + } + + var progressSection2 = jobProgressReporter.CreateSection("Checking out OpenDream version", 0.5f); + + await repo.CheckoutObject( + version.SourceCommittish, + null, + null, + true, + progressSection2, + cancellationToken); + + return new RepositoryEngineInstallationData(IOManager, repo, InstallationRepositorySubDirectory); + } + catch + { + repo?.Dispose(); + throw; + } + } + + /// + public override async ValueTask Install(ByondVersion version, string installPath, CancellationToken cancellationToken) + { + CheckVersionValidity(version); + ArgumentNullException.ThrowIfNull(installPath); var dotnetPaths = DotnetHelper.GetPotentialDotnetPaths(platformIdentifier.IsWindows) .ToList(); @@ -92,8 +158,33 @@ public override async ValueTask Install(ByondVersion version, string path, Cance var dotnetPath = dotnetPaths[selectedPathIndex]; - await Task.Yield(); - throw new NotImplementedException(); + var repositoryPath = IOManager.ConcatPath(installPath, InstallationRepositorySubDirectory); + + await using (var buildProcess = processExecutor.LaunchProcess( + dotnetPath, + repositoryPath, + "build -c Release", + null, + true, + true)) + { + var buildExitCode = await buildProcess.Lifetime; + if (buildExitCode != 0) + throw new JobException("OpenDream build failed!"); + } + + const string BinDirectory = "bin"; + await IOManager.MoveDirectory( + IOManager.ConcatPath( + repositoryPath, + BinDirectory, + "Content.Server"), + IOManager.ConcatPath( + installPath, + BinDirectory), + cancellationToken); + + await IOManager.DeleteDirectory(repositoryPath, cancellationToken); } /// @@ -110,21 +201,5 @@ public override ValueTask TrustDmbPath(string fullDmbPath, CancellationToken can ArgumentNullException.ThrowIfNull(fullDmbPath); return ValueTask.CompletedTask; } - - /// - protected override async ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken) - { - throw new NotImplementedException("This won't work because of the goddamn fucking robust toolbox submodule"); - var fullCommit = await gitHubService.GetCommit("OpenDreamProject", "OpenDream", version.SourceCommittish, cancellationToken); - - if (fullCommit.Sha != version.SourceCommittish) - { - Logger.LogInformation("Replacing committish {committish} with full SHA {sha}...", version.SourceCommittish, fullCommit.Sha); - version.SourceCommittish = fullCommit.Sha; - } - - var gitHubDownloadUrlString = $"https://codeload.github.com/OpenDreamProject/OpenDream/zip/{version.SourceCommittish}"; - return new Uri(gitHubDownloadUrlString); - } } } diff --git a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs index 06831bb98fa..ed3785cfbd2 100644 --- a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs @@ -58,7 +58,7 @@ public PosixByondInstaller( IIOManager ioManager, IFileDownloader fileDownloader, ILogger logger) - : base(ioManager, fileDownloader, logger) + : base(ioManager, logger, fileDownloader) { this.postWriteHandler = postWriteHandler ?? throw new ArgumentNullException(nameof(postWriteHandler)); diff --git a/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs b/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs new file mode 100644 index 00000000000..88fbb779117 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +using Tgstation.Server.Host.Components.Repository; +using Tgstation.Server.Host.IO; + +namespace Tgstation.Server.Host.Components.Engine +{ + /// + /// Implementation of using a . + /// + sealed class RepositoryEngineInstallationData : IEngineInstallationData + { + /// + /// The for the . + /// + readonly IIOManager ioManager; + + /// + /// The backing . + /// + readonly IRepository repository; + + /// + /// The name of the subdirectory the is copied to. + /// + readonly string targetSubDirectory; + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + /// The value of . + public RepositoryEngineInstallationData(IIOManager ioManager, IRepository repository, string targetSubDirectory) + { + this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.repository = repository ?? throw new ArgumentNullException(nameof(repository)); + this.targetSubDirectory = targetSubDirectory ?? throw new ArgumentNullException(nameof(targetSubDirectory)); + } + + /// + public ValueTask DisposeAsync() + { + repository.Dispose(); + return ValueTask.CompletedTask; + } + + /// + public Task ExtractToPath(string path, CancellationToken cancellationToken) + => repository.CopyTo( + ioManager.ConcatPath( + path, + targetSubDirectory), + cancellationToken) + .AsTask(); + } +} diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 1d9336af8f1..7795a69b6be 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -96,7 +96,7 @@ public WindowsByondInstaller( IFileDownloader fileDownloader, IOptions generalConfigurationOptions, ILogger logger) - : base(ioManager, fileDownloader, logger) + : base(ioManager, logger, fileDownloader) { this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); diff --git a/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs b/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs new file mode 100644 index 00000000000..292b7259817 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs @@ -0,0 +1,43 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +using Tgstation.Server.Host.IO; + +namespace Tgstation.Server.Host.Components.Engine +{ + /// + /// Implementation of for a zip file in a . + /// + sealed class ZipStreamEngineInstallationData : IEngineInstallationData + { + /// + /// The for the . + /// + readonly IIOManager ioManager; + + /// + /// The containing the zip data of the engine. + /// + readonly Stream zipStream; + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + public ZipStreamEngineInstallationData(IIOManager ioManager, Stream zipStream) + { + this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.zipStream = zipStream ?? throw new ArgumentNullException(nameof(zipStream)); + } + + /// + public ValueTask DisposeAsync() => zipStream.DisposeAsync(); + + /// + public Task ExtractToPath(string path, CancellationToken cancellationToken) + => ioManager.ZipToDirectory(path, zipStream, cancellationToken); + } +} diff --git a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs index 7b02f6d177f..668e158241d 100644 --- a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs @@ -61,6 +61,11 @@ public sealed class GeneralConfiguration : ServerInformationBase /// const uint DefaultShutdownTimeoutMinutes = 300; + /// + /// The default value for . + /// + const string DefaultOpenDreamGitUrl = "https://github.com/OpenDreamProject/OpenDream"; + /// /// The current . /// @@ -122,6 +127,11 @@ public sealed class GeneralConfiguration : ServerInformationBase /// public uint? DeploymentDirectoryCopyTasksPerCore { get; set; } + /// + /// Location of a publically accessible OpenDream repository. + /// + public Uri OpenDreamGitUrl { get; set; } = new Uri(DefaultOpenDreamGitUrl); + /// /// Initializes a new instance of the class. /// diff --git a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs index e17ac8a4906..4e57ddc2dea 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using Tgstation.Server.Api.Models; @@ -51,7 +52,7 @@ public async Task TestDownload() var mockFileDownloader = new Mock(); var installer = new PosixByondInstaller(mockPostWriteHandler.Object, mockIOManager.Object, mockFileDownloader.Object, mockLogger.Object); - await Assert.ThrowsExceptionAsync(() => installer.DownloadVersion(null, default).AsTask()); + await Assert.ThrowsExceptionAsync(() => installer.DownloadVersion(null, null, default).AsTask()); var ourArray = Array.Empty(); mockFileDownloader @@ -64,15 +65,20 @@ public async Task TestDownload() new MemoryStream(ourArray))) .Verifiable(); - var result = await installer.DownloadVersion(new ByondVersion + var result = ExtractMemoryStreamFromInstallationData(await installer.DownloadVersion(new ByondVersion { Engine = EngineType.Byond, Version = new Version(123, 252345), - }, default); + }, null, default)); Assert.IsTrue(ourArray.SequenceEqual(result.ToArray())); mockIOManager.Verify(); } + static MemoryStream ExtractMemoryStreamFromInstallationData(IEngineInstallationData engineInstallationData) + { + var zipStreamData = (ZipStreamEngineInstallationData)engineInstallationData; + return (MemoryStream)zipStreamData.GetType().GetField("stream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData); + } [TestMethod] public async Task TestInstallByond() diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index 16e059e70ee..0aa49b4a53a 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -254,7 +254,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) using var windowsByondInstaller = byondInstaller as WindowsByondInstaller; // get the bytes for stable - using var stableBytesMs = await byondInstaller.DownloadVersion(testVersion, cancellationToken); + using var stableBytesMs = TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(testVersion, null, cancellationToken)); var test = await byondClient.SetActiveVersion( new ByondVersionRequest diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 0ab2cb1acf5..7dd1e992533 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -158,7 +158,7 @@ public async Task RunCompatTests( // get the bytes for stable ByondInstallResponse installJob2; - using (var stableBytesMs = await byondInstaller.DownloadVersion(compatVersion, cancellationToken)) + using (var stableBytesMs = TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(compatVersion, null, cancellationToken))) { installJob2 = await instanceClient.Byond.SetActiveVersion(new ByondVersionRequest { diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 06cce64ee77..eac841d7bc7 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -127,13 +127,15 @@ await CachingFileDownloader.InitializeByondVersion( const string ArchiveEntryPath = "byond/bin/dd.exe"; var hasEntry = ArchiveHasFileEntry( - await byondInstaller.DownloadVersion( - new ByondVersion - { - Engine = EngineType.Byond, - Version = WindowsByondInstaller.DDExeVersion - }, - default), + TestingUtils.ExtractMemoryStreamFromInstallationData( + await byondInstaller.DownloadVersion( + new ByondVersion + { + Engine = EngineType.Byond, + Version = WindowsByondInstaller.DDExeVersion + }, + null, + default)), ArchiveEntryPath); Assert.IsTrue(hasEntry); @@ -218,13 +220,15 @@ await TestMapThreadsVersion( Engine = EngineType.Byond, Version = MapThreadsVersion(), }, - await byondInstaller.DownloadVersion( - new ByondVersion - { - Engine = EngineType.Byond, - Version = MapThreadsVersion() - }, - default), + TestingUtils.ExtractMemoryStreamFromInstallationData( + await byondInstaller.DownloadVersion( + new ByondVersion + { + Engine = EngineType.Byond, + Version = MapThreadsVersion() + }, + null, + default)), byondInstaller, ioManager, processExecutor, @@ -400,7 +404,7 @@ static string GetMigrationTimestampString(Type type) => type Assert.AreEqual(latestMigrationSL, DatabaseContext.SLLatestMigration); } - static async Task> GetByondVersionPriorTo(IEngineInstaller byondInstaller, Version version) + static async Task> GetByondVersionPriorTo(ByondInstallerBase byondInstaller, Version version) { var minusOneMinor = new Version(version.Major, version.Minor - 1); var byondVersion = new ByondVersion @@ -410,17 +414,19 @@ static async Task> GetByondVersionPriorTo(IEng }; try { - return Tuple.Create(await byondInstaller.DownloadVersion( + return Tuple.Create(TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion( byondVersion, - CancellationToken.None), byondVersion); + null, + CancellationToken.None)), byondVersion); } catch (HttpRequestException) { var minusOneMajor = new Version(minusOneMinor.Major - 1, minusOneMinor.Minor); byondVersion.Version = minusOneMajor; - return Tuple.Create(await byondInstaller.DownloadVersion( + return Tuple.Create(TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion( byondVersion, - CancellationToken.None), byondVersion); + null, + CancellationToken.None)), byondVersion); } } diff --git a/tests/Tgstation.Server.Tests/TestingUtils.cs b/tests/Tgstation.Server.Tests/TestingUtils.cs index d4f8d8caa32..cef9f817cfb 100644 --- a/tests/Tgstation.Server.Tests/TestingUtils.cs +++ b/tests/Tgstation.Server.Tests/TestingUtils.cs @@ -1,10 +1,13 @@ using System; +using System.IO; +using System.Reflection; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; +using Tgstation.Server.Host.Components.Engine; + namespace Tgstation.Server.Tests { static class TestingUtils @@ -25,5 +28,11 @@ public static ILoggerFactory CreateLoggerFactoryForLogger(ILogger logger, out Mo .Verifiable(); return mockLoggerFactory.Object; } + + public static MemoryStream ExtractMemoryStreamFromInstallationData(IEngineInstallationData engineInstallationData) + { + var zipStreamData = (ZipStreamEngineInstallationData)engineInstallationData; + return (MemoryStream)zipStreamData.GetType().GetField("stream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData); + } } } From f00cb55fc34906937fdce9ed836f73bc0b7db581 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 12 Oct 2023 21:47:14 -0400 Subject: [PATCH 036/717] Setup dependency injection for mapping IEngineInstallers and global OD repo manager Various other things to get it compiling --- .../Chat/Providers/DiscordProvider.cs | 127 ++++++++++-------- .../Chat/Providers/ProviderFactory.cs | 15 ++- .../Components/Deployment/DreamMaker.cs | 52 +++---- .../Engine/DelegatingEngineInstaller.cs | 70 ++++++++++ .../Components/Engine/IEngineInstallation.cs | 2 +- .../Engine/OpenDreamInstallation.cs | 6 +- .../Components/Engine/OpenDreamInstaller.cs | 9 +- .../Components/Events/NoopEventConsumer.cs | 16 +++ .../Components/InstanceFactory.cs | 61 +++------ .../Repository/IRepositoryManagerFactory.cs | 19 +++ .../Repository/RepostoryManagerFactory.cs | 100 ++++++++++++++ .../Configuration/GeneralConfiguration.cs | 10 ++ .../Controllers/ByondController.cs | 56 +++++--- src/Tgstation.Server.Host/Core/Application.cs | 30 ++++- src/Tgstation.Server.Host/appsettings.yml | 2 + .../Chat/Providers/TestDiscordProvider.cs | 19 +-- 16 files changed, 424 insertions(+), 170 deletions(-) create mode 100644 src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs create mode 100644 src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs create mode 100644 src/Tgstation.Server.Host/Components/Repository/IRepositoryManagerFactory.cs create mode 100644 src/Tgstation.Server.Host/Components/Repository/RepostoryManagerFactory.cs diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 492eb8e332f..013f22fc369 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -25,6 +25,7 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components.Interop; +using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Models; @@ -69,6 +70,11 @@ public override string BotMention /// readonly IAssemblyInformationProvider assemblyInformationProvider; + /// + /// The for the . + /// + readonly GeneralConfiguration generalConfiguration; + /// /// The containing Discord services. /// @@ -126,63 +132,6 @@ public override string BotMention /// The normalized mention . static string NormalizeMentions(string fromDiscord) => fromDiscord.Replace("<@!", "<@", StringComparison.Ordinal); - /// - /// Create a of s for a discord update embed. - /// - /// The of the deployment. - /// The of the deployment. - /// The repository GitHub owner, if any. - /// The repository GitHub name, if any. - /// if the local deployment commit was pushed to the remote repository. - /// A new of s to use. - static List BuildUpdateEmbedFields( - Models.RevisionInformation revisionInformation, - ByondVersion byondVersion, - string gitHubOwner, - string gitHubRepo, - bool localCommitPushed) - { - bool gitHub = gitHubOwner != null && gitHubRepo != null; - var engineField = byondVersion.Engine.Value switch - { - EngineType.Byond => new EmbedField( - "BYOND Version", - $"{byondVersion.Version.Major}.{byondVersion.Version.Minor}{(byondVersion.Version.Build > 0 ? $".{byondVersion.Version.Build}" : String.Empty)}", - true), - EngineType.OpenDream => new EmbedField( - "OpenDream Version", - $"[{byondVersion.SourceCommittish[..7]}](https://github.com/OpenDreamProject/OpenDream/commit/{revisionInformation.CommitSha})", - true), - _ => throw new InvalidOperationException($"Invaild EngineType: {byondVersion.Engine.Value}"), - }; - - var fields = new List - { - engineField, - new EmbedField( - "Local Commit", - localCommitPushed && gitHub - ? $"[{revisionInformation.CommitSha[..7]}](https://github.com/{gitHubOwner}/{gitHubRepo}/commit/{revisionInformation.CommitSha})" - : revisionInformation.CommitSha[..7], - true), - new EmbedField( - "Branch Commit", - gitHub - ? $"[{revisionInformation.OriginCommitSha[..7]}](https://github.com/{gitHubOwner}/{gitHubRepo}/commit/{revisionInformation.OriginCommitSha})" - : revisionInformation.OriginCommitSha[..7], - true), - }; - - fields.AddRange((revisionInformation.ActiveTestMerges ?? Enumerable.Empty()) - .Select(x => x.TestMerge) - .Select(x => new EmbedField( - $"#{x.Number}", - $"[{x.TitleAtMerge}]({x.Url}) by _[@{x.Author}](https://github.com/{x.Author})_{Environment.NewLine}Commit: [{x.TargetCommitSha[..7]}](https://github.com/{gitHubOwner}/{gitHubRepo}/commit/{x.TargetCommitSha}){(String.IsNullOrWhiteSpace(x.Comment) ? String.Empty : $"{Environment.NewLine}_**{x.Comment}**_")}", - false))); - - return fields; - } - /// /// Initializes a new instance of the class. /// @@ -191,15 +140,18 @@ static List BuildUpdateEmbedFields( /// The for the . /// The value of . /// The for the . + /// The value of . public DiscordProvider( IJobManager jobManager, IAsyncDelayer asyncDelayer, ILogger logger, IAssemblyInformationProvider assemblyInformationProvider, - ChatBot chatBot) + ChatBot chatBot, + GeneralConfiguration generalConfiguration) : base(jobManager, asyncDelayer, logger, chatBot) { this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); + this.generalConfiguration = generalConfiguration ?? throw new ArgumentNullException(nameof(generalConfiguration)); mappedChannels = new List(); connectDisconnectLock = new object(); @@ -903,12 +855,69 @@ async ValueTask> GetGuildChannels(IPartialGuild guild) return allAccessibleChannels; } + /// + /// Create a of s for a discord update embed. + /// + /// The of the deployment. + /// The of the deployment. + /// The repository GitHub owner, if any. + /// The repository GitHub name, if any. + /// if the local deployment commit was pushed to the remote repository. + /// A new of s to use. + List BuildUpdateEmbedFields( + Models.RevisionInformation revisionInformation, + ByondVersion byondVersion, + string gitHubOwner, + string gitHubRepo, + bool localCommitPushed) + { + bool gitHub = gitHubOwner != null && gitHubRepo != null; + var engineField = byondVersion.Engine.Value switch + { + EngineType.Byond => new EmbedField( + "BYOND Version", + $"{byondVersion.Version.Major}.{byondVersion.Version.Minor}{(byondVersion.Version.Build > 0 ? $".{byondVersion.Version.Build}" : String.Empty)}", + true), + EngineType.OpenDream => new EmbedField( + "OpenDream Version", + $"[{byondVersion.SourceCommittish[..7]}]({generalConfiguration.OpenDreamGitUrl}/commit/{revisionInformation.CommitSha})", + true), + _ => throw new InvalidOperationException($"Invaild EngineType: {byondVersion.Engine.Value}"), + }; + + var fields = new List + { + engineField, + new EmbedField( + "Local Commit", + localCommitPushed && gitHub + ? $"[{revisionInformation.CommitSha[..7]}](https://github.com/{gitHubOwner}/{gitHubRepo}/commit/{revisionInformation.CommitSha})" + : revisionInformation.CommitSha[..7], + true), + new EmbedField( + "Branch Commit", + gitHub + ? $"[{revisionInformation.OriginCommitSha[..7]}](https://github.com/{gitHubOwner}/{gitHubRepo}/commit/{revisionInformation.OriginCommitSha})" + : revisionInformation.OriginCommitSha[..7], + true), + }; + + fields.AddRange((revisionInformation.ActiveTestMerges ?? Enumerable.Empty()) + .Select(x => x.TestMerge) + .Select(x => new EmbedField( + $"#{x.Number}", + $"[{x.TitleAtMerge}]({x.Url}) by _[@{x.Author}](https://github.com/{x.Author})_{Environment.NewLine}Commit: [{x.TargetCommitSha[..7]}](https://github.com/{gitHubOwner}/{gitHubRepo}/commit/{x.TargetCommitSha}){(String.IsNullOrWhiteSpace(x.Comment) ? String.Empty : $"{Environment.NewLine}_**{x.Comment}**_")}", + false))); + + return fields; + } + /// /// Convert a to an parameters. /// /// The to convert. /// The parameter for sending a single . - #pragma warning disable CA1502 +#pragma warning disable CA1502 Optional> ConvertEmbed(ChatEmbed embed) { if (embed == null) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs index eeed8c15838..ed3608b92da 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs @@ -2,8 +2,10 @@ using System.Globalization; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Tgstation.Server.Api.Models; +using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; @@ -33,6 +35,11 @@ sealed class ProviderFactory : IProviderFactory /// readonly ILoggerFactory loggerFactory; + /// + /// The for the . + /// + readonly GeneralConfiguration generalConfiguration; + /// /// Initializes a new instance of the class. /// @@ -40,16 +47,19 @@ sealed class ProviderFactory : IProviderFactory /// The value of . /// The value of . /// The value of . + /// The containing the value of . public ProviderFactory( IJobManager jobManager, IAssemblyInformationProvider assemblyInformationProvider, IAsyncDelayer asyncDelayer, - ILoggerFactory loggerFactory) + ILoggerFactory loggerFactory, + IOptions generalConfigurationOptions) { this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); + generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } /// @@ -69,7 +79,8 @@ public IProvider CreateProvider(Models.ChatBot settings) asyncDelayer, loggerFactory.CreateLogger(), assemblyInformationProvider, - settings), + settings, + generalConfiguration), _ => throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid ChatProvider: {0}", settings.Provider)), }; } diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index 6a5f5242253..8dd925f8124 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -864,39 +864,29 @@ async ValueTask VerifyApi( async ValueTask RunDreamMaker(IEngineExecutableLock engineLock, Models.CompileJob job, CancellationToken cancellationToken) { var arguments = engineLock.FormatCompilerArguments($"{job.DmeName}.{DmeExtension}"); - bool result; - if (arguments == null) - { - logger.LogTrace("Engine lock says compilation isn't necessary."); - job.Output = $"{engineLock.Version.Engine} does not require compilation."; - result = true; - } - else - { - await using var dm = processExecutor.LaunchProcess( - engineLock.CompilerExePath, - ioManager.ResolvePath( - job.DirectoryName.ToString()), - arguments, - readStandardHandles: true, - noShellExecute: true); - - if (sessionConfiguration.LowPriorityDeploymentProcesses) - dm.AdjustPriority(false); - - int exitCode; - using (cancellationToken.Register(() => dm.Terminate())) - exitCode = (await dm.Lifetime).Value; - cancellationToken.ThrowIfCancellationRequested(); - - logger.LogDebug("DreamMaker exit code: {exitCode}", exitCode); - job.Output = $"{await dm.GetCombinedOutput(cancellationToken)}{Environment.NewLine}{Environment.NewLine}Exit Code: {exitCode}"; - logger.LogDebug("DreamMaker output: {newLine}{output}", Environment.NewLine, job.Output); - result = exitCode == 0; - } + + await using var dm = processExecutor.LaunchProcess( + engineLock.CompilerExePath, + ioManager.ResolvePath( + job.DirectoryName.ToString()), + arguments, + readStandardHandles: true, + noShellExecute: true); + + if (sessionConfiguration.LowPriorityDeploymentProcesses) + dm.AdjustPriority(false); + + int exitCode; + using (cancellationToken.Register(() => dm.Terminate())) + exitCode = (await dm.Lifetime).Value; + cancellationToken.ThrowIfCancellationRequested(); + + logger.LogDebug("DreamMaker exit code: {exitCode}", exitCode); + job.Output = $"{await dm.GetCombinedOutput(cancellationToken)}{Environment.NewLine}{Environment.NewLine}Exit Code: {exitCode}"; + logger.LogDebug("DreamMaker output: {newLine}{output}", Environment.NewLine, job.Output); currentDreamMakerOutput = job.Output; - return result; + return exitCode == 0; } /// diff --git a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs new file mode 100644 index 00000000000..19fde5df738 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Common.Extensions; +using Tgstation.Server.Host.Jobs; + +namespace Tgstation.Server.Host.Components.Engine +{ + /// + /// Implementation of that forwards calls to different based on their appropriate . + /// + sealed class DelegatingEngineInstaller : IEngineInstaller + { + /// + /// The mapping s to their appropriate . + /// + readonly IReadOnlyDictionary delegatedInstallers; + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + public DelegatingEngineInstaller(IReadOnlyDictionary delegatedInstallers) + { + this.delegatedInstallers = delegatedInstallers ?? throw new ArgumentNullException(nameof(delegatedInstallers)); + } + + /// + public Task CleanCache(CancellationToken cancellationToken) + => Task.WhenAll(delegatedInstallers.Values.Select(installer => installer.CleanCache(cancellationToken))); + + /// + public IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask) + => DelegateCall(version, installer => installer.CreateInstallation(version, installationTask)); + + /// + public ValueTask DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken) + => DelegateCall(version, installer => installer.DownloadVersion(version, jobProgressReporter, cancellationToken)); + + /// + public ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken) + => DelegateCall(version, installer => installer.Install(version, path, cancellationToken)); + + /// + public ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken) + => ValueTaskExtensions.WhenAll(delegatedInstallers.Values.Select(installer => installer.TrustDmbPath(fullDmbPath, cancellationToken))); + + /// + public ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken) + => DelegateCall(version, installer => installer.UpgradeInstallation(version, path, cancellationToken)); + + /// + /// Delegate a given to its appropriate . + /// + /// The return of the call. + /// The used to perform delegate selection. + /// The that will be called with the correct based on . + /// The value of the delegated call. + TReturn DelegateCall(ByondVersion version, Func call) + { + ArgumentNullException.ThrowIfNull(version); + return call(delegatedInstallers[version.Engine.Value]); + } + } +} diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs index 75ebbab4c87..238b4fea117 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs @@ -59,7 +59,7 @@ string FormatServerArguments( /// Return the command line arguments for compiling a given if compilation is necessary. /// /// The full path to the .dme to compile. - /// An arguments if compilation is required, otherwise. + /// The formatted arguments . string FormatCompilerArguments(string dmePath); } } diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index cdff39ed41c..5a3d04d6d22 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -54,6 +54,10 @@ public OpenDreamInstallation( /// public string FormatServerArguments(IDmbProvider dmbProvider, IReadOnlyDictionary parameters, DreamDaemonLaunchParameters launchParameters, string logFilePath) { + ArgumentNullException.ThrowIfNull(dmbProvider); + ArgumentNullException.ThrowIfNull(parameters); + ArgumentNullException.ThrowIfNull(launchParameters); + throw new NotImplementedException(); } @@ -61,7 +65,7 @@ public string FormatServerArguments(IDmbProvider dmbProvider, IReadOnlyDictionar public string FormatCompilerArguments(string dmePath) { ArgumentNullException.ThrowIfNull(dmePath); - return null; + throw new NotImplementedException(); } } } diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 976131743c7..9eb60f0dfe1 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -8,6 +8,7 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Common; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Configuration; @@ -120,14 +121,20 @@ await repo.FetchOrigin( var progressSection2 = jobProgressReporter.CreateSection("Checking out OpenDream version", 0.5f); + var committish = version.SourceCommittish; + if (committish == null) + committish = $"{generalConfiguration.OpenDreamGitTagPrefix}{version.Version.Semver()}"; + await repo.CheckoutObject( - version.SourceCommittish, + committish, null, null, true, progressSection2, cancellationToken); + version.SourceCommittish = repo.Head; + return new RepositoryEngineInstallationData(IOManager, repo, InstallationRepositorySubDirectory); } catch diff --git a/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs new file mode 100644 index 00000000000..a8b07e4d7e0 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Tgstation.Server.Host.Components.Events +{ + /// + /// No-op implementation of . + /// + sealed class NoopEventConsumer : IEventConsumer + { + /// + public ValueTask HandleEvent(EventType eventType, IEnumerable parameters, bool deploymentPipeline, CancellationToken cancellationToken) + => ValueTask.CompletedTask; + } +} diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index 0199f1de087..e45052ecd15 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -111,14 +111,9 @@ sealed class InstanceFactory : IInstanceFactory readonly IPlatformIdentifier platformIdentifier; /// - /// The for the . + /// The for the . /// - readonly ILibGit2RepositoryFactory repositoryFactory; - - /// - /// The for the . - /// - readonly ILibGit2Commands repositoryCommands; + readonly IRepositoryManagerFactory repositoryManagerFactory; /// /// The for the . @@ -130,11 +125,6 @@ sealed class InstanceFactory : IInstanceFactory /// readonly IFileTransferTicketProvider fileTransferService; - /// - /// The for the . - /// - readonly IGitRemoteFeaturesFactory gitRemoteFeaturesFactory; - /// /// The for the . /// @@ -182,11 +172,9 @@ sealed class InstanceFactory : IInstanceFactory /// The value of . /// The value of . /// The value of . - /// The value of . - /// The value of . + /// The value of . /// The value of . /// The value of . - /// The value of . /// The value of . /// The value of . /// The containing the value of . @@ -208,11 +196,9 @@ public InstanceFactory( IJobManager jobManager, INetworkPromptReaper networkPromptReaper, IPlatformIdentifier platformIdentifier, - ILibGit2RepositoryFactory repositoryFactory, - ILibGit2Commands repositoryCommands, + IRepositoryManagerFactory repositoryManagerFactory, IServerPortProvider serverPortProvider, IFileTransferTicketProvider fileTransferService, - IGitRemoteFeaturesFactory gitRemoteFeaturesFactory, IRemoteDeploymentManagerFactory remoteDeploymentManagerFactory, IAsyncDelayer asyncDelayer, IOptions generalConfigurationOptions, @@ -234,11 +220,9 @@ public InstanceFactory( this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); this.networkPromptReaper = networkPromptReaper ?? throw new ArgumentNullException(nameof(networkPromptReaper)); this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); - this.repositoryFactory = repositoryFactory ?? throw new ArgumentNullException(nameof(repositoryFactory)); - this.repositoryCommands = repositoryCommands ?? throw new ArgumentNullException(nameof(repositoryCommands)); + this.repositoryManagerFactory = repositoryManagerFactory ?? throw new ArgumentNullException(nameof(repositoryManagerFactory)); this.serverPortProvider = serverPortProvider ?? throw new ArgumentNullException(nameof(serverPortProvider)); this.fileTransferService = fileTransferService ?? throw new ArgumentNullException(nameof(fileTransferService)); - this.gitRemoteFeaturesFactory = gitRemoteFeaturesFactory ?? throw new ArgumentNullException(nameof(gitRemoteFeaturesFactory)); this.remoteDeploymentManagerFactory = remoteDeploymentManagerFactory ?? throw new ArgumentNullException(nameof(remoteDeploymentManagerFactory)); this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); @@ -284,19 +268,10 @@ public async ValueTask CreateInstance(IBridgeRegistrar bridgeRegistra generalConfiguration, sessionConfiguration); var eventConsumer = new EventConsumer(configuration); - var repoManager = new RepositoryManager( - repositoryFactory, - repositoryCommands, - repoIoManager, - eventConsumer, - postWriteHandler, - gitRemoteFeaturesFactory, - loggerFactory.CreateLogger(), - loggerFactory.CreateLogger(), - generalConfiguration); + var repoManager = repositoryManagerFactory.CreateRepositoryManager(repoIoManager, eventConsumer); try { - var byond = new EngineManager(byondIOManager, engineInstaller, eventConsumer, loggerFactory.CreateLogger()); + var engineManager = new EngineManager(byondIOManager, engineInstaller, eventConsumer, loggerFactory.CreateLogger()); var dmbFactory = new DmbFactory( databaseContextFactory, @@ -307,7 +282,7 @@ public async ValueTask CreateInstance(IBridgeRegistrar bridgeRegistra metadata); try { - var commandFactory = new CommandFactory(assemblyInformationProvider, byond, repoManager, databaseContextFactory, dmbFactory, metadata); + var commandFactory = new CommandFactory(assemblyInformationProvider, engineManager, repoManager, databaseContextFactory, dmbFactory, metadata); var chatManager = chatFactory.CreateChatManager(commandFactory, metadata.ChatSettings); try @@ -321,7 +296,7 @@ public async ValueTask CreateInstance(IBridgeRegistrar bridgeRegistra var sessionControllerFactory = new SessionControllerFactory( processExecutor, - byond, + engineManager, topicClientFactory, cryptographySuite, assemblyInformationProvider, @@ -357,7 +332,7 @@ public async ValueTask CreateInstance(IBridgeRegistrar bridgeRegistra Instance instance = null; var dreamMaker = new DreamMaker( - byond, + engineManager, gameIoManager, configuration, sessionControllerFactory, @@ -375,7 +350,7 @@ public async ValueTask CreateInstance(IBridgeRegistrar bridgeRegistra instance = new Instance( metadata, repoManager, - byond, + engineManager, dreamMaker, watchdog, chatManager, @@ -417,18 +392,12 @@ public async ValueTask CreateInstance(IBridgeRegistrar bridgeRegistra /// public Task StartAsync(CancellationToken cancellationToken) - { - CheckSystemCompatibility(); - return engineInstaller.CleanCache(cancellationToken); - } + => Task.WhenAll( + repositoryManagerFactory.StartAsync(cancellationToken), + engineInstaller.CleanCache(cancellationToken)); /// - public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; - - /// - /// Test that the is functional. - /// - void CheckSystemCompatibility() => repositoryFactory.CreateInMemory(); + public Task StopAsync(CancellationToken cancellationToken) => repositoryManagerFactory.StopAsync(cancellationToken); /// /// Create the for a given set of instance . diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManagerFactory.cs b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManagerFactory.cs new file mode 100644 index 00000000000..0e8c54c70e9 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManagerFactory.cs @@ -0,0 +1,19 @@ +using Tgstation.Server.Host.Components.Events; +using Tgstation.Server.Host.IO; + +namespace Tgstation.Server.Host.Components.Repository +{ + /// + /// Factory for creating s. + /// + interface IRepositoryManagerFactory : IComponentService + { + /// + /// Create a . + /// + /// The to use. + /// The to use. + /// A new . + IRepositoryManager CreateRepositoryManager(IIOManager ioManager, IEventConsumer eventConsumer); + } +} diff --git a/src/Tgstation.Server.Host/Components/Repository/RepostoryManagerFactory.cs b/src/Tgstation.Server.Host/Components/Repository/RepostoryManagerFactory.cs new file mode 100644 index 00000000000..cba66ff69a4 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Repository/RepostoryManagerFactory.cs @@ -0,0 +1,100 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +using Tgstation.Server.Host.Components.Events; +using Tgstation.Server.Host.Configuration; +using Tgstation.Server.Host.IO; + +namespace Tgstation.Server.Host.Components.Repository +{ + /// + sealed class RepostoryManagerFactory : IRepositoryManagerFactory + { + /// + /// The for the . + /// + readonly ILibGit2RepositoryFactory repositoryFactory; + + /// + /// The for the . + /// + readonly ILibGit2Commands repositoryCommands; + + /// + /// The for the . + /// + readonly IPostWriteHandler postWriteHandler; + + /// + /// The for the . + /// + readonly IGitRemoteFeaturesFactory gitRemoteFeaturesFactory; + + /// + /// The for the . + /// + readonly ILoggerFactory loggerFactory; + + /// + /// The for the . + /// + readonly GeneralConfiguration generalConfiguration; + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + /// The value of . + /// The value of . + /// The value of . + /// The containing the value of . + public RepostoryManagerFactory( + ILibGit2RepositoryFactory repositoryFactory, + ILibGit2Commands repositoryCommands, + IPostWriteHandler postWriteHandler, + IGitRemoteFeaturesFactory gitRemoteFeaturesFactory, + ILoggerFactory loggerFactory, + IOptions generalConfigurationOptions) + { + this.repositoryFactory = repositoryFactory ?? throw new ArgumentNullException(nameof(repositoryFactory)); + this.repositoryCommands = repositoryCommands ?? throw new ArgumentNullException(nameof(repositoryCommands)); + this.postWriteHandler = postWriteHandler ?? throw new ArgumentNullException(nameof(postWriteHandler)); + this.gitRemoteFeaturesFactory = gitRemoteFeaturesFactory ?? throw new ArgumentNullException(nameof(gitRemoteFeaturesFactory)); + this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); + generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); + } + + /// + public IRepositoryManager CreateRepositoryManager(IIOManager ioManager, IEventConsumer eventConsumer) + => new RepositoryManager( + repositoryFactory, + repositoryCommands, + ioManager, + eventConsumer, + postWriteHandler, + gitRemoteFeaturesFactory, + loggerFactory.CreateLogger(), + loggerFactory.CreateLogger(), + generalConfiguration); + + /// + public Task StartAsync(CancellationToken cancellationToken) + { + CheckSystemCompatibility(); + return Task.CompletedTask; + } + + /// + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + + /// + /// Test that the is functional. + /// + void CheckSystemCompatibility() => repositoryFactory.CreateInMemory(); + } +} diff --git a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs index 668e158241d..eecca9cd9ff 100644 --- a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs @@ -66,6 +66,11 @@ public sealed class GeneralConfiguration : ServerInformationBase /// const string DefaultOpenDreamGitUrl = "https://github.com/OpenDreamProject/OpenDream"; + /// + /// The default value for . + /// + const string DefaultOpenDreamGitTagPrefix = "v"; + /// /// The current . /// @@ -132,6 +137,11 @@ public sealed class GeneralConfiguration : ServerInformationBase /// public Uri OpenDreamGitUrl { get; set; } = new Uri(DefaultOpenDreamGitUrl); + /// + /// The prefix to the OpenDream semver as tags appear in the git repository. + /// + public string OpenDreamGitTagPrefix { get; set; } = DefaultOpenDreamGitTagPrefix; + /// /// Initializes a new instance of the class. /// diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index 34ab4684319..b57df144fc0 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -9,6 +9,7 @@ using Tgstation.Server.Api; using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Api.Rights; @@ -72,7 +73,7 @@ public ByondController( } /// - /// Gets the active . + /// Gets the active . /// /// A resulting in the for the operation. /// Retrieved version information successfully. @@ -91,7 +92,7 @@ public ValueTask Read() : Conflict(new ErrorMessageResponse(ErrorCode.ResourceNotPresent)))); /// - /// Lists installed s. + /// Lists installed s. /// /// The current page. /// The page size. @@ -139,15 +140,11 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode #pragma warning restore CA1506 #pragma warning restore CA1502 { - throw new NotImplementedException("Fix OD/BYOND model validation"); - ArgumentNullException.ThrowIfNull(model); + var earlyOut = ValidateByondVersion(model); + if (earlyOut != null) + return earlyOut; var uploadingZip = model.UploadCustomZip == true; - var isByondEngine = model.Engine.Value == EngineType.Byond; - - if ((isByondEngine && (model.Version.Revision != -1 || (uploadingZip && model.Version.Build > 0) || model.SourceCommittish != null)) - || (!isByondEngine && (model.Version != null || String.IsNullOrWhiteSpace(model.SourceCommittish)))) - return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); var userByondRights = AuthenticationContext.InstancePermissionSet.ByondRights.Value; if ((!userByondRights.HasFlag(ByondRights.InstallOfficialOrChangeActiveByondVersion) && !uploadingZip) @@ -201,7 +198,7 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode Instance.Id); // run the install through the job manager - var job = new Job + var job = new Models.Job { Description = $"Install {(!uploadingZip ? String.Empty : "custom ")}{model.Engine.Value} version {model.Version}", StartedBy = AuthenticationContext.User, @@ -271,7 +268,7 @@ await core.EngineManager.ChangeVersion( /// A resulting in the for the operation. /// Created to delete target version successfully. /// Attempted to delete the active BYOND . - /// The specified was not installed. + /// The specified was not installed. [HttpDelete] [TgsAuthorize(ByondRights.DeleteInstall)] [ProducesResponseType(typeof(JobResponse), 202)] @@ -279,13 +276,9 @@ await core.EngineManager.ChangeVersion( [ProducesResponseType(typeof(ErrorMessageResponse), 410)] public async ValueTask Delete([FromBody] ByondVersionDeleteRequest model, CancellationToken cancellationToken) { - ArgumentNullException.ThrowIfNull(model); - - if (model.Version.Revision != -1) - return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); - - if (model.Engine == EngineType.Byond) - model.Version = NormalizeByondVersion(model.Version); + var earlyOut = ValidateByondVersion(model); + if (earlyOut != null) + return earlyOut; var notInstalledResponse = await WithComponentInstance( instance => @@ -310,7 +303,7 @@ public async ValueTask Delete([FromBody] ByondVersionDeleteReques var isByondVersion = model.Engine.Value == EngineType.Byond; // run the install through the job manager - var job = new Job + var job = new Models.Job { Description = $"Delete installed {model.Engine.Value} version {model.Version}", StartedBy = AuthenticationContext.User, @@ -333,5 +326,30 @@ await jobManager.RegisterOperation( var apiResponse = job.ToApi(); return Accepted(apiResponse); } + + /// + /// Validate and normalize a given . + /// + /// The to validate and normalize. + /// The to return, if any. + BadRequestObjectResult ValidateByondVersion(ByondVersion version) + { + ArgumentNullException.ThrowIfNull(version); + + var isByond = version.Engine.Value == EngineType.Byond; + if ((isByond + && (version.Version == null + || version.Version.Revision != -1 + || version.SourceCommittish != null)) + || (version.Engine.Value == EngineType.OpenDream && + ((version.SourceCommittish == null && version.Version == null) + || (version.Version != null && (version.Version.Revision != -1 || version.Version.Build == -1 || version.SourceCommittish == null))))) + return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); + + if (isByond) + version.Version = NormalizeByondVersion(version.Version); + + return null; + } } } diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index eaeeb9a9541..b0fbbf31698 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -27,11 +27,13 @@ using Serilog.Sinks.Elasticsearch; using Tgstation.Server.Api; +using Tgstation.Server.Api.Models; using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment.Remote; using Tgstation.Server.Host.Components.Engine; +using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.Components.Repository; @@ -332,7 +334,7 @@ void AddTypedContext() AddWatchdog(services, postSetupServices); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -345,7 +347,7 @@ void AddTypedContext() AddWatchdog(services, postSetupServices); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -357,6 +359,29 @@ void AddTypedContext() services.AddHostedService(); } + // only global repo manager should be for the OD repo + var openDreamRepositoryDirectory = ioManager.ConcatPath( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + assemblyInformationProvider.VersionPrefix, + "OpenDreamRepository"); + services.AddSingleton( + services => services + .GetRequiredService() + .CreateRepositoryManager( + new ResolvingIOManager( + services.GetRequiredService(), + openDreamRepositoryDirectory), + new NoopEventConsumer())); + + services.AddSingleton(); + services.AddSingleton( + serviceProvider => new Dictionary + { + { EngineType.Byond, serviceProvider.GetRequiredService() }, + { EngineType.OpenDream, serviceProvider.GetRequiredService() }, + }); + services.AddSingleton(); + if (postSetupServices.InternalConfiguration.UsingSystemD) services.AddHostedService(); @@ -378,6 +403,7 @@ void AddTypedContext() services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddChatProviderFactory(); services.AddSingleton(); diff --git a/src/Tgstation.Server.Host/appsettings.yml b/src/Tgstation.Server.Host/appsettings.yml index bebeb79c043..30463394955 100644 --- a/src/Tgstation.Server.Host/appsettings.yml +++ b/src/Tgstation.Server.Host/appsettings.yml @@ -16,6 +16,8 @@ General: HostApiDocumentation: false # Make HTTP API documentation available at /swagger/v1/swagger.json SkipAddingByondFirewallException: false # Windows Only: Prevent running netsh.exe to add a firewall exception for installed DreamDaemon binaries DeploymentDirectoryCopyTasksPerCore: 100 # Maximum number of concurrent file copy operations PER available CPU core + OpenDreamGitUrl: https://github.com/OpenDreamProject/OpenDream # The repository to retrieve OpenDream from + OpenDreamGitTagPrefix: v # The prefix to the OpenDream semver as tags appear in the git repository Session: HighPriorityLiveDreamDaemon: false # If DreamDaemon instances should run as higher priority processes LowPriorityDeploymentProcesses: true # If TGS Deployments should run as lower priority processes diff --git a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs index 210b31447ed..b21b19f0aee 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs @@ -8,6 +8,7 @@ using Moq; using Tgstation.Server.Api.Models; +using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Models; using Tgstation.Server.Host.System; @@ -52,15 +53,17 @@ public async Task TestConstructionAndDisposal() ReconnectionInterval = 1, }; - Assert.ThrowsException(() => new DiscordProvider(null, null, null, null, null)); - Assert.ThrowsException(() => new DiscordProvider(mockJobManager, null, null, null, null)); + Assert.ThrowsException(() => new DiscordProvider(null, null, null, null, null, null)); + Assert.ThrowsException(() => new DiscordProvider(mockJobManager, null, null, null, null, null)); var mockDel = Mock.Of(); - Assert.ThrowsException(() => new DiscordProvider(mockJobManager, mockDel, null, null, null)); + Assert.ThrowsException(() => new DiscordProvider(mockJobManager, mockDel, null, null, null, null)); var mockLogger = Mock.Of>(); - Assert.ThrowsException(() => new DiscordProvider(mockJobManager, mockDel, mockLogger, null, null)); + Assert.ThrowsException(() => new DiscordProvider(mockJobManager, mockDel, mockLogger, null, null, null)); var mockAss = Mock.Of(); - Assert.ThrowsException(() => new DiscordProvider(mockJobManager, mockDel, mockLogger, mockAss, null)); - await new DiscordProvider(mockJobManager, mockDel, mockLogger, mockAss, bot).DisposeAsync(); + Assert.ThrowsException(() => new DiscordProvider(mockJobManager, mockDel, mockLogger, mockAss, null, null)); + Assert.ThrowsException(() => new DiscordProvider(mockJobManager, mockDel, mockLogger, mockAss, bot, null)); + var mockGen = new GeneralConfiguration(); + await new DiscordProvider(mockJobManager, mockDel, mockLogger, mockAss, bot, mockGen).DisposeAsync(); } static ValueTask InvokeConnect(IProvider provider, CancellationToken cancellationToken = default) => (ValueTask)provider.GetType().GetMethod("Connect", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(provider, new object[] { cancellationToken }); @@ -73,7 +76,7 @@ public async Task TestConnectWithFakeTokenFails() { ReconnectionInterval = 1, ConnectionString = "asdf" - }); + }, new GeneralConfiguration()); await Assert.ThrowsExceptionAsync(async () => await InvokeConnect(provider)); Assert.IsFalse(provider.Connected); } @@ -88,7 +91,7 @@ public async Task TestConnectAndDisconnect() Assert.Fail("TGS_TEST_DISCORD_TOKEN is not a valid Discord connection string!"); var mockLogger = new Mock>(); - await using var provider = new DiscordProvider(mockJobManager, Mock.Of(), mockLogger.Object, Mock.Of(), testToken1); + await using var provider = new DiscordProvider(mockJobManager, Mock.Of(), mockLogger.Object, Mock.Of(), testToken1, new GeneralConfiguration()); Assert.IsFalse(provider.Connected); await InvokeConnect(provider); Assert.IsTrue(provider.Connected); From 10a0937945664bd0856745917ba6603d12b37c33 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 12 Oct 2023 22:13:35 -0400 Subject: [PATCH 037/717] Slowly pulling OpenDream stuff together --- build/Version.props | 2 +- src/Tgstation.Server.Api/Models/ErrorCode.cs | 2 +- .../Session/SessionControllerFactory.cs | 7 +++++-- src/Tgstation.Server.Host/Core/Application.cs | 2 +- .../Components/Engine/TestPosixByondInstaller.cs | 2 +- .../Tgstation.Server.Tests/Live/TestLiveServer.cs | 15 +++++++++------ tests/Tgstation.Server.Tests/TestingUtils.cs | 2 +- 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/build/Version.props b/build/Version.props index 782ee29423f..3d8d79e6960 100644 --- a/build/Version.props +++ b/build/Version.props @@ -9,7 +9,7 @@ 6.0.1 12.0.0 13.0.0 - 6.5.3 + 6.6.0 5.6.1 1.4.0 1.2.1 diff --git a/src/Tgstation.Server.Api/Models/ErrorCode.cs b/src/Tgstation.Server.Api/Models/ErrorCode.cs index 9b51e8f9bb7..fd9b92075d3 100644 --- a/src/Tgstation.Server.Api/Models/ErrorCode.cs +++ b/src/Tgstation.Server.Api/Models/ErrorCode.cs @@ -477,7 +477,7 @@ public enum ErrorCode : uint /// Attempted to launch DreamDaemon on a user account that had the BYOND pager running. /// [Description("Cannot start DreamDaemon headless with the BYOND pager running!")] - DeploymentPagerRunning, + DreamDaemonPagerRunning, /// /// Could not bind to port we wanted to launch DreamDaemon on. diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 3bd4744a649..6e529714f78 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -250,7 +250,10 @@ public async ValueTask LaunchNew( dmbProvider.CompileJob.Id); PortBindTest(launchParameters.Port.Value); - await CheckPagerIsNotRunning(); + + // mad this isn't abstracted but whatever + if (dmbProvider.ByondVersion.Engine.Value == EngineType.Byond) + await CheckPagerIsNotRunning(); string outputFilePath = null; var preserveLogFile = true; @@ -615,7 +618,7 @@ async ValueTask CheckPagerIsNotRunning() var ourUsername = ourProcess.GetExecutingUsername(); if (otherUsername.Equals(ourUsername, StringComparison.Ordinal)) - throw new JobException(ErrorCode.DeploymentPagerRunning); + throw new JobException(ErrorCode.DreamDaemonPagerRunning); } } } diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index b0fbbf31698..4931fc9302b 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -374,7 +374,7 @@ void AddTypedContext() new NoopEventConsumer())); services.AddSingleton(); - services.AddSingleton( + services.AddSingleton>( serviceProvider => new Dictionary { { EngineType.Byond, serviceProvider.GetRequiredService() }, diff --git a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs index 4e57ddc2dea..f98cb4dc1ac 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs @@ -77,7 +77,7 @@ public async Task TestDownload() static MemoryStream ExtractMemoryStreamFromInstallationData(IEngineInstallationData engineInstallationData) { var zipStreamData = (ZipStreamEngineInstallationData)engineInstallationData; - return (MemoryStream)zipStreamData.GetType().GetField("stream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData); + return (MemoryStream)zipStreamData.GetType().GetField("zipStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData); } [TestMethod] diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 0b98971e3eb..3b0c80abdaf 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1046,14 +1046,17 @@ async Task TestTgsInternal(EngineType engineType, CancellationToken hardCancella Assert.IsTrue(new IrcConnectionStringBuilder(ircConnectionString).Valid); } - var procs = System.Diagnostics.Process.GetProcessesByName("byond"); - if (procs.Any()) + if (engineType == EngineType.Byond) { - foreach (var proc in procs) - proc.Dispose(); + var procs = System.Diagnostics.Process.GetProcessesByName("byond"); + if (procs.Any()) + { + foreach (var proc in procs) + proc.Dispose(); - // Inconclusive and not fail because we don't want to unexpectedly kill a dev's BYOND.exe - Assert.Inconclusive("Cannot run server test because DreamDaemon will not start headless while the BYOND pager is running!"); + // Inconclusive and not fail because we don't want to unexpectedly kill a dev's BYOND.exe + Assert.Inconclusive("Cannot run server test because DreamDaemon will not start headless while the BYOND pager is running!"); + } } using var server = new LiveTestingServer(null, true); diff --git a/tests/Tgstation.Server.Tests/TestingUtils.cs b/tests/Tgstation.Server.Tests/TestingUtils.cs index cef9f817cfb..7b4a62fc248 100644 --- a/tests/Tgstation.Server.Tests/TestingUtils.cs +++ b/tests/Tgstation.Server.Tests/TestingUtils.cs @@ -32,7 +32,7 @@ public static ILoggerFactory CreateLoggerFactoryForLogger(ILogger logger, out Mo public static MemoryStream ExtractMemoryStreamFromInstallationData(IEngineInstallationData engineInstallationData) { var zipStreamData = (ZipStreamEngineInstallationData)engineInstallationData; - return (MemoryStream)zipStreamData.GetType().GetField("stream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData); + return (MemoryStream)zipStreamData.GetType().GetField("zipStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData); } } } From d4b3583ff3b606b035408f3b41aedd0991e562a5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 00:21:45 -0400 Subject: [PATCH 038/717] More OpenDream Integration - Make use of `world.opendream_topic_port` in DMAPI if present. Send in initial bridge request. - Implement compiler and server arguments for `OpenDreamInstallation`. - Deprecate bridge port update requests. - Prevent symlink swapping if not running a BYOND engine. --- build/Version.props | 2 +- src/DMAPI/tgs/v5/__interop_version.dm | 2 +- src/DMAPI/tgs/v5/_defines.dm | 2 +- src/DMAPI/tgs/v5/api.dm | 9 +- src/DMAPI/tgs/v5/topic.dm | 1 + src/DMAPI/tgs/v5/undefs.dm | 2 +- .../Internal/DreamDaemonLaunchParameters.cs | 10 +-- .../Components/Deployment/DmbProvider.cs | 15 ++-- .../Components/Deployment/DmbProviderBase.cs | 37 ++++++++ .../Components/Deployment/DreamMaker.cs | 6 -- .../Deployment/TemporaryDmbProvider.cs | 19 ++-- .../Engine/OpenDreamInstallation.cs | 41 +++++++-- .../Components/Engine/OpenDreamInstaller.cs | 72 ++++++++++++--- .../Interop/Bridge/BridgeCommandType.cs | 2 +- .../Interop/Bridge/BridgeParameters.cs | 7 +- .../Components/Session/ISessionController.cs | 17 ++-- .../Components/Session/SessionController.cs | 90 +++---------------- .../Components/Watchdog/BasicWatchdog.cs | 5 ++ .../Components/Watchdog/WindowsWatchdog.cs | 11 +++ 19 files changed, 205 insertions(+), 145 deletions(-) create mode 100644 src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs diff --git a/build/Version.props b/build/Version.props index 3d8d79e6960..05c5365352d 100644 --- a/build/Version.props +++ b/build/Version.props @@ -10,7 +10,7 @@ 12.0.0 13.0.0 6.6.0 - 5.6.1 + 5.7.0 1.4.0 1.2.1 2.0.0 diff --git a/src/DMAPI/tgs/v5/__interop_version.dm b/src/DMAPI/tgs/v5/__interop_version.dm index 5d3d491a736..83420d130a7 100644 --- a/src/DMAPI/tgs/v5/__interop_version.dm +++ b/src/DMAPI/tgs/v5/__interop_version.dm @@ -1 +1 @@ -"5.6.1" +"5.7.0" diff --git a/src/DMAPI/tgs/v5/_defines.dm b/src/DMAPI/tgs/v5/_defines.dm index f973338daa0..b4557c562c8 100644 --- a/src/DMAPI/tgs/v5/_defines.dm +++ b/src/DMAPI/tgs/v5/_defines.dm @@ -8,7 +8,6 @@ #define DMAPI5_TOPIC_REQUEST_LIMIT 65528 #define DMAPI5_TOPIC_RESPONSE_LIMIT 65529 -#define DMAPI5_BRIDGE_COMMAND_PORT_UPDATE 0 #define DMAPI5_BRIDGE_COMMAND_STARTUP 1 #define DMAPI5_BRIDGE_COMMAND_PRIME 2 #define DMAPI5_BRIDGE_COMMAND_REBOOT 3 @@ -18,6 +17,7 @@ #define DMAPI5_PARAMETER_ACCESS_IDENTIFIER "accessIdentifier" #define DMAPI5_PARAMETER_CUSTOM_COMMANDS "customCommands" +#define DMAPI5_PARAMETER_TOPIC_PORT "topicPort" #define DMAPI5_CHUNK "chunk" #define DMAPI5_CHUNK_PAYLOAD "payload" diff --git a/src/DMAPI/tgs/v5/api.dm b/src/DMAPI/tgs/v5/api.dm index 34cc43f8762..cb8a2f11f73 100644 --- a/src/DMAPI/tgs/v5/api.dm +++ b/src/DMAPI/tgs/v5/api.dm @@ -38,7 +38,7 @@ var/datum/tgs_version/api_version = ApiVersion() version = null - var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands())) + var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands(), DMAPI5_PARAMETER_TOPIC_PORT = GetTopicPort())) if(!istype(bridge_response)) TGS_ERROR_LOG("Failed initial bridge request!") return FALSE @@ -100,6 +100,13 @@ initialized = TRUE return TRUE +/datum/tgs_api/v5/proc/GetTopicPort() +#if defined(OPENDREAM) && defined(OPENDREAM_TOPIC_PORT_EXISTS) + return "[world.opendream_topic_port]" +#else + return null +#endif + /datum/tgs_api/v5/proc/RequireInitialBridgeResponse() TGS_DEBUG_LOG("RequireInitialBridgeResponse()") var/logged = FALSE diff --git a/src/DMAPI/tgs/v5/topic.dm b/src/DMAPI/tgs/v5/topic.dm index d7d47121381..40ab80e4657 100644 --- a/src/DMAPI/tgs/v5/topic.dm +++ b/src/DMAPI/tgs/v5/topic.dm @@ -175,6 +175,7 @@ var/list/reattach_response = TopicResponse(error_message) reattach_response[DMAPI5_PARAMETER_CUSTOM_COMMANDS] = ListCustomCommands() + reattach_response[DMAPI5_PARAMETER_TOPIC_PORT] = GetTopicPort() return reattach_response if(DMAPI5_TOPIC_COMMAND_SEND_CHUNK) diff --git a/src/DMAPI/tgs/v5/undefs.dm b/src/DMAPI/tgs/v5/undefs.dm index c679737dfc4..f579cbefb7a 100644 --- a/src/DMAPI/tgs/v5/undefs.dm +++ b/src/DMAPI/tgs/v5/undefs.dm @@ -8,7 +8,6 @@ #undef DMAPI5_TOPIC_REQUEST_LIMIT #undef DMAPI5_TOPIC_RESPONSE_LIMIT -#undef DMAPI5_BRIDGE_COMMAND_PORT_UPDATE #undef DMAPI5_BRIDGE_COMMAND_STARTUP #undef DMAPI5_BRIDGE_COMMAND_PRIME #undef DMAPI5_BRIDGE_COMMAND_REBOOT @@ -18,6 +17,7 @@ #undef DMAPI5_PARAMETER_ACCESS_IDENTIFIER #undef DMAPI5_PARAMETER_CUSTOM_COMMANDS +#undef DMAPI5_PARAMETER_TOPIC_PORT #undef DMAPI5_CHUNK #undef DMAPI5_CHUNK_PAYLOAD diff --git a/src/Tgstation.Server.Api/Models/Internal/DreamDaemonLaunchParameters.cs b/src/Tgstation.Server.Api/Models/Internal/DreamDaemonLaunchParameters.cs index b563d955855..b21ce258ff0 100644 --- a/src/Tgstation.Server.Api/Models/Internal/DreamDaemonLaunchParameters.cs +++ b/src/Tgstation.Server.Api/Models/Internal/DreamDaemonLaunchParameters.cs @@ -9,21 +9,21 @@ namespace Tgstation.Server.Api.Models.Internal public class DreamDaemonLaunchParameters { /// - /// If the BYOND web client can be used to connect to the game server. + /// If the BYOND web client can be used to connect to the game server. No-op for . /// [Required] [ResponseOptions] public bool? AllowWebClient { get; set; } /// - /// If -profile is passed in on the DreamDaemon command line. + /// If -profile is passed in on the DreamDaemon command line. No-op for . /// [Required] [ResponseOptions] public bool? StartProfiler { get; set; } /// - /// The level of DreamDaemon. + /// The level of DreamDaemon. No-op for . /// [Required] [ResponseOptions] @@ -31,7 +31,7 @@ public class DreamDaemonLaunchParameters public DreamDaemonVisibility? Visibility { get; set; } /// - /// The level of DreamDaemon. + /// The level of DreamDaemon. No-op for . /// [Required] [ResponseOptions] @@ -92,7 +92,7 @@ public class DreamDaemonLaunchParameters public bool? LogOutput { get; set; } /// - /// If DreamDaemon supports it, the value added as the -map-threads parameter. 0 uses the default BYOND value. + /// If DreamDaemon supports it, the value added as the -map-threads parameter. 0 uses the default BYOND value. No-op for . /// [Required] [ResponseOptions] diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs index 554cc28cdd5..2b58ba17c0b 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs @@ -6,19 +6,16 @@ namespace Tgstation.Server.Host.Components.Deployment { /// - sealed class DmbProvider : IDmbProvider + sealed class DmbProvider : DmbProviderBase, IDmbProvider { /// - public string DmbName => String.Concat(CompileJob.DmeName, DreamMaker.DmbExtension); + public override string Directory => ioManager.ResolvePath(CompileJob.DirectoryName.ToString() + directoryAppend); /// - public string Directory => ioManager.ResolvePath(CompileJob.DirectoryName.ToString() + directoryAppend); + public override Models.CompileJob CompileJob { get; } /// - public Models.CompileJob CompileJob { get; } - - /// - public ByondVersion ByondVersion { get; } + public override ByondVersion ByondVersion { get; } /// /// The for the . @@ -53,9 +50,9 @@ public DmbProvider(Models.CompileJob compileJob, ByondVersion byondVersion, IIOM } /// - public void Dispose() => onDispose?.Invoke(); + public override void Dispose() => onDispose?.Invoke(); /// - public void KeepAlive() => onDispose = null; + public override void KeepAlive() => onDispose = null; } } diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs new file mode 100644 index 00000000000..ea792bd23d5 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs @@ -0,0 +1,37 @@ +using System; + +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Models; + +namespace Tgstation.Server.Host.Components.Deployment +{ + /// + abstract class DmbProviderBase : IDmbProvider + { + /// + public string DmbName => String.Concat( + CompileJob.DmeName, + ByondVersion.Engine.Value switch + { + EngineType.Byond => ".dmb", + EngineType.OpenDream => ".json", + _ => throw new InvalidOperationException($"Invalid EngineType: {ByondVersion.Engine.Value}"), + }); + + /// + public abstract string Directory { get; } + + /// + public abstract Models.CompileJob CompileJob { get; } + + /// + public abstract ByondVersion ByondVersion { get; } + + /// + public abstract void Dispose(); + + /// + public abstract void KeepAlive(); + } +} diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index 8dd925f8124..cc7c03b0012 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -30,11 +30,6 @@ namespace Tgstation.Server.Host.Components.Deployment /// sealed class DreamMaker : IDreamMaker { - /// - /// Extension for .dmbs. - /// - public const string DmbExtension = ".dmb"; - /// /// Extension for .dmes. /// @@ -805,7 +800,6 @@ async ValueTask VerifyApi( ApiValidationStatus validationStatus; using (var provider = new TemporaryDmbProvider( ioManager.ResolvePath(job.DirectoryName.ToString()), - String.Concat(job.DmeName, DmbExtension), job, byondLock.Version)) await using (var controller = await sessionControllerFactory.LaunchNew(provider, byondLock, launchParameters, true, cancellationToken)) diff --git a/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs index 5ecc6b96709..a94efe35ed4 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs @@ -7,41 +7,36 @@ namespace Tgstation.Server.Host.Components.Deployment /// /// Temporary . /// - sealed class TemporaryDmbProvider : IDmbProvider + sealed class TemporaryDmbProvider : DmbProviderBase { /// - public string DmbName { get; } + public override string Directory { get; } /// - public string Directory { get; } + public override Models.CompileJob CompileJob { get; } /// - public Models.CompileJob CompileJob { get; } - - /// - public ByondVersion ByondVersion { get; } + public override ByondVersion ByondVersion { get; } /// /// Initializes a new instance of the class. /// /// The value of . - /// The value of . /// The value of . /// The value of . - public TemporaryDmbProvider(string directory, string dmb, Models.CompileJob compileJob, ByondVersion byondVersion) + public TemporaryDmbProvider(string directory, Models.CompileJob compileJob, ByondVersion byondVersion) { - DmbName = dmb ?? throw new ArgumentNullException(nameof(dmb)); Directory = directory ?? throw new ArgumentNullException(nameof(directory)); CompileJob = compileJob ?? throw new ArgumentNullException(nameof(compileJob)); ByondVersion = byondVersion ?? throw new ArgumentNullException(nameof(byondVersion)); } /// - public void Dispose() + public override void Dispose() { } /// - public void KeepAlive() => throw new NotSupportedException(); + public override void KeepAlive() => throw new NotSupportedException(); } } diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index 5a3d04d6d22..6d1fc3377a4 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; +using System.Web; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; @@ -34,21 +36,23 @@ sealed class OpenDreamInstallation : IEngineInstallation /// /// Initializes a new instance of the class. /// + /// The value of . + /// The value of . /// The value of . /// The value of . public OpenDreamInstallation( + string serverExePath, + string compilerExePath, Task installationTask, ByondVersion version) { + ServerExePath = serverExePath ?? throw new ArgumentNullException(nameof(serverExePath)); + CompilerExePath = compilerExePath ?? throw new ArgumentNullException(nameof(compilerExePath)); InstallationTask = installationTask ?? throw new ArgumentNullException(nameof(installationTask)); ArgumentNullException.ThrowIfNull(version); if (version.Engine.Value != EngineType.OpenDream) throw new ArgumentException($"Invalid EngineType: {version.Engine.Value}", nameof(version)); - - Version = version ?? throw new ArgumentNullException(nameof(version)); - - throw new NotImplementedException(); } /// @@ -58,14 +62,33 @@ public string FormatServerArguments(IDmbProvider dmbProvider, IReadOnlyDictionar ArgumentNullException.ThrowIfNull(parameters); ArgumentNullException.ThrowIfNull(launchParameters); - throw new NotImplementedException(); + var parametersString = String.Join(';', parameters.Select(kvp => $"{kvp.Key}={kvp.Value}")); + + if (!String.IsNullOrEmpty(launchParameters.AdditionalParameters)) + { + // TGS and BYOND expect url encoded params, OD takes unencoded + var unencodedAdditionalParams = String.Join( + ';', + launchParameters + .AdditionalParameters + .Split('&') + .Select( + singleParam => String.Join( + '=', + singleParam + .Split('=') + .Select( + encodedParam => HttpUtility.UrlDecode(encodedParam))))); + + parametersString = $"{parametersString};{unencodedAdditionalParams}"; + } + + var arguments = $"--cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" \"{dmbProvider.DmbName}\""; + return arguments; } /// public string FormatCompilerArguments(string dmePath) - { - ArgumentNullException.ThrowIfNull(dmePath); - throw new NotImplementedException(); - } + => $"--suppress-unimplemented --verbose --notices-enabled {dmePath ?? throw new ArgumentNullException(nameof(dmePath))}"; } } diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 9eb60f0dfe1..3021238614a 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -23,10 +23,15 @@ namespace Tgstation.Server.Host.Components.Engine /// sealed class OpenDreamInstaller : EngineInstallerBase { + /// + /// The name of the subdirectory used to store the server and compiler binaries. + /// + const string InstallationBinDirectory = "bin"; + /// /// The name of the subdirectory used for the 's copy. /// - private const string InstallationRepositorySubDirectory = "SourceRepo"; + const string InstallationSourceSubDirectory = "TgsSourceSubdir"; /// protected override EngineType TargetEngineType => EngineType.OpenDream; @@ -82,7 +87,21 @@ public OpenDreamInstaller( public override IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask) { CheckVersionValidity(version); - return new OpenDreamInstallation(installationTask, version); + var binPathForVersion = IOManager.ConcatPath(version.ToString(), InstallationBinDirectory); + + var exeExtension = platformIdentifier.IsWindows + ? ".exe" + : String.Empty; + + return new OpenDreamInstallation( + IOManager.ConcatPath( + binPathForVersion, + $"OpenDreamServer{exeExtension}"), + IOManager.ConcatPath( + binPathForVersion, + $"DMCompiler{exeExtension}"), + installationTask, + version); } /// @@ -135,7 +154,7 @@ await repo.CheckoutObject( version.SourceCommittish = repo.Head; - return new RepositoryEngineInstallationData(IOManager, repo, InstallationRepositorySubDirectory); + return new RepositoryEngineInstallationData(IOManager, repo, InstallationSourceSubDirectory); } catch { @@ -149,6 +168,40 @@ public override async ValueTask Install(ByondVersion version, string installPath { CheckVersionValidity(version); ArgumentNullException.ThrowIfNull(installPath); + var sourcePath = IOManager.ConcatPath(installPath, InstallationSourceSubDirectory); + + if (!await IOManager.DirectoryExists(sourcePath, cancellationToken)) + { + // a zip install that didn't come from us? + // we want to use the bin dir, so put everything where we expect + Logger.LogDebug("Correcting extraction location..."); + var dirsTask = IOManager.GetDirectories(installPath, cancellationToken); + var filesTask = IOManager.GetFiles(installPath, cancellationToken); + var dirCreateTask = IOManager.CreateDirectory(sourcePath, cancellationToken); + + await Task.WhenAll(dirsTask, filesTask, dirCreateTask); + + var dirsMoveTasks = dirsTask + .Result + .Select( + dirPath => IOManager.MoveDirectory( + dirPath, + IOManager.ConcatPath( + sourcePath, + IOManager.GetFileName(sourcePath)), + cancellationToken)); + var filesMoveTask = filesTask + .Result + .Select( + filePath => IOManager.MoveFile( + filePath, + IOManager.ConcatPath( + sourcePath, + IOManager.GetFileName(sourcePath)), + cancellationToken)); + + await Task.WhenAll(dirsMoveTasks.Concat(filesMoveTask)); + } var dotnetPaths = DotnetHelper.GetPotentialDotnetPaths(platformIdentifier.IsWindows) .ToList(); @@ -165,11 +218,9 @@ public override async ValueTask Install(ByondVersion version, string installPath var dotnetPath = dotnetPaths[selectedPathIndex]; - var repositoryPath = IOManager.ConcatPath(installPath, InstallationRepositorySubDirectory); - await using (var buildProcess = processExecutor.LaunchProcess( dotnetPath, - repositoryPath, + sourcePath, "build -c Release", null, true, @@ -180,18 +231,17 @@ public override async ValueTask Install(ByondVersion version, string installPath throw new JobException("OpenDream build failed!"); } - const string BinDirectory = "bin"; await IOManager.MoveDirectory( IOManager.ConcatPath( - repositoryPath, - BinDirectory, + sourcePath, + InstallationBinDirectory, "Content.Server"), IOManager.ConcatPath( installPath, - BinDirectory), + InstallationBinDirectory), cancellationToken); - await IOManager.DeleteDirectory(repositoryPath, cancellationToken); + await IOManager.DeleteDirectory(sourcePath, cancellationToken); } /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeCommandType.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeCommandType.cs index ad3c2273569..627d55d9949 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeCommandType.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeCommandType.cs @@ -8,7 +8,7 @@ public enum BridgeCommandType /// /// DreamDaemon notifying us of its current port and requesting a change if necessary. /// - PortUpdate, + DeprecatedPortUpdate, /// /// DreamDaemon notifying it is starting. diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs index 6bd13cb72d8..c1c9213063c 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs @@ -17,7 +17,7 @@ public sealed class BridgeParameters : DMApiParameters public BridgeCommandType? CommandType { get; set; } /// - /// The current port for requests. + /// The current port for requests. /// public ushort? CurrentPort { get; set; } @@ -45,5 +45,10 @@ public sealed class BridgeParameters : DMApiParameters /// The for requests. /// public ChunkData Chunk { get; set; } + + /// + /// The port that should be used to send world topics, if not the default. + /// + public ushort? TopicPort { get; set; } } } diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs index a42186c66b9..ba894c941c9 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs @@ -2,9 +2,9 @@ using System.Threading; using System.Threading.Tasks; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Components.Interop.Topic; -using Tgstation.Server.Host.Models; using Tgstation.Server.Host.System; namespace Tgstation.Server.Host.Components.Session @@ -37,7 +37,12 @@ interface ISessionController : IProcessBase, IRenameNotifyee, IAsyncDisposable /// /// Gets the associated with the . /// - CompileJob CompileJob { get; } + Models.CompileJob CompileJob { get; } + + /// + /// Gets the associated with the . + /// + ByondVersion ByondVersion { get; } /// /// Gets the associated with the . @@ -98,14 +103,6 @@ interface ISessionController : IProcessBase, IRenameNotifyee, IAsyncDisposable /// A resulting in the of /world/Topic(). ValueTask SendCommand(TopicParameters parameters, CancellationToken cancellationToken); - /// - /// Causes the world to start listening on a . - /// - /// The port to change to. - /// The for the operation. - /// A resulting in if the operation succeeded, otherwise. - Task SetPort(ushort newPort, CancellationToken cancellatonToken); - /// /// Attempts to change the current to . /// diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index f8a9a928f90..3802387b615 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -14,6 +14,7 @@ using Serilog.Context; using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; @@ -51,6 +52,9 @@ public ApiValidationStatus ApiValidationStatus /// public Models.CompileJob CompileJob => ReattachInformation.Dmb.CompileJob; + /// + public ByondVersion ByondVersion => ReattachInformation.Dmb.ByondVersion; + /// public RebootState RebootState => ReattachInformation.RebootState; @@ -167,11 +171,6 @@ async Task Wrap() /// readonly object synchronizationLock; - /// - /// The waits on when DreamDaemon currently has it's ports closed. - /// - TaskCompletionSource portAssignmentTcs; - /// /// The that completes when DD sends a valid startup bridge request. /// @@ -197,11 +196,6 @@ async Task Wrap() /// volatile uint rebootBridgeRequestsProcessing; - /// - /// The port to assign DreamDaemon when it queries for it. - /// - ushort? nextPort; - /// /// The for the . /// @@ -484,40 +478,6 @@ void LogCombinedResponse() return fullResponse; } - /// - public Task SetPort(ushort port, CancellationToken cancellationToken) - { - CheckDisposed(); - - if (port == 0) - throw new ArgumentOutOfRangeException(nameof(port), port, "port must not be zero!"); - - async Task ImmediateTopicPortChange() - { - var commandResult = await SendCommand( - new TopicParameters(port), - cancellationToken); - - if (commandResult?.ErrorMessage != null) - return false; - - ReattachInformation.Port = port; - return true; - } - - lock (synchronizationLock) - if (portClosedForReboot) - { - if (portAssignmentTcs != null) - throw new InvalidOperationException("A port change operation is already in progress!"); - nextPort = port; - portAssignmentTcs = new TaskCompletionSource(); - return portAssignmentTcs.Task; - } - else - return ImmediateTopicPortChange(); - } - /// public async ValueTask SetRebootState(RebootState newRebootState, CancellationToken cancellationToken) { @@ -702,37 +662,8 @@ async ValueTask ProcessBridgeCommand(BridgeParameters parameters TerminationWasRequested = true; process.Terminate(); break; - case BridgeCommandType.PortUpdate: - lock (synchronizationLock) - { - if (!parameters.CurrentPort.HasValue) - { - /////UHHHH - Logger.LogWarning("DreamDaemon sent new port command without providing it's own!"); - return BridgeError("Missing stringified port as data parameter!"); - } - - var currentPort = parameters.CurrentPort.Value; - if (!nextPort.HasValue) - ReattachInformation.Port = parameters.CurrentPort.Value; // not ready yet, so what we'll do is accept the random port DD opened on for now and change it later when we decide to - else - { - // nextPort is ready, tell DD to switch to that - // if it fails it'll kill itself - response.NewPort = nextPort.Value; - ReattachInformation.Port = nextPort.Value; - nextPort = null; - - // we'll also get here from SetPort so complete that task - var tmpTcs = portAssignmentTcs; - portAssignmentTcs = null; - tmpTcs.SetResult(true); - } - - portClosedForReboot = false; - } - - break; + case BridgeCommandType.DeprecatedPortUpdate: + return BridgeError("Port switching is no longer supported!"); case BridgeCommandType.Startup: apiValidationStatus = ApiValidationStatus.BadValidationRequest; if (parameters.Version == null) @@ -774,6 +705,13 @@ async ValueTask ProcessBridgeCommand(BridgeParameters parameters ReattachInformation.RuntimeInformation.ServerPort, ReattachInformation.RuntimeInformation.ApiValidateOnly); + if (parameters.TopicPort.HasValue) + { + var newTopicPort = parameters.TopicPort.Value; + Logger.LogInformation("Server is requesting use of port {topicPort} for topic communications", newTopicPort); + ReattachInformation.Port = newTopicPort; + } + // Load custom commands chatTrackingContext.CustomCommands = parameters.CustomCommands; Interlocked.Exchange(ref startupTcs, new TaskCompletionSource()).SetResult(); @@ -816,7 +754,7 @@ async ValueTask ProcessBridgeCommand(BridgeParameters parameters /// A new errored . BridgeResponse BridgeError(string message) { - Logger.LogWarning("Bridge request chunking error: {message}", message); + Logger.LogWarning("Bridge request error: {message}", message); return new BridgeResponse { ErrorMessage = message, diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index fa9159527d4..dc15334e75d 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -255,6 +255,11 @@ await ReattachFailure( await CheckLaunchResult(Server, "Server", cancellationToken); Server.EnableCustomChatCommands(); + + // persist again, because the DMAPI can say we need a different topic port (Original OD behavior) + // kinda hacky imo, but at least we can safely forget about this + if (!reattachInProgress) + await SessionPersistor.Save(Server.ReattachInformation, cancellationToken); } catch (Exception ex) { diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs index cdc5307352e..af112dae3ef 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; +using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; @@ -245,6 +246,16 @@ protected override async ValueTask HandleNewDmbAvailable(CancellationToken cance canSeamlesslySwap = false; } + if (Server.ByondVersion.Engine.Value != EngineType.Byond + || compileJobProvider.ByondVersion.Engine.Value != EngineType.Byond) + { + Logger.LogDebug( + "Not swapping to new compile job {newCompileJobId} as it or the current compile job ({oldCompileJobId}) is not using the BYOND engine. Queueing graceful restart instead...", + compileJobProvider.CompileJob.Id, + Server.CompileJob.Id); + canSeamlesslySwap = false; + } + if (!canSeamlesslySwap) { compileJobProvider.Dispose(); From 1b8759be3323ae740fdce9a8efcf1ce667b37e42 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 00:21:51 -0400 Subject: [PATCH 039/717] Some monitor cleanups --- .../Components/Watchdog/WatchdogBase.cs | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index 3847e26077c..522424daddd 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -817,30 +817,24 @@ async Task MonitorLifetimes(CancellationToken cancellationToken) void UpdateMonitoredTasks() { - static void TryUpdateTask(ref Task oldTask, Func newTaskFactory) + var sameController = lastController == controller; + void TryUpdateTask(ref Task oldTask, Func newTaskFactory) { - if (oldTask?.IsCompleted == true) + if (sameController && oldTask?.IsCompleted == true) return; oldTask = newTaskFactory(); } controller.RebootGate = nextMonitorWakeupTcs.Task; - if (lastController == controller) - { - TryUpdateTask(ref activeServerLifetime, () => controller.Lifetime); - TryUpdateTask(ref activeServerReboot, () => controller.OnReboot); - TryUpdateTask(ref serverPrimed, () => controller.OnPrime); - TryUpdateTask(ref activeServerStartup, () => controller.OnStartup); - } - else - { - activeServerLifetime = controller.Lifetime; - activeServerReboot = controller.OnReboot; - serverPrimed = controller.OnPrime; - activeServerStartup = controller.OnStartup; + + TryUpdateTask(ref activeServerLifetime, () => controller.Lifetime); + TryUpdateTask(ref activeServerReboot, () => controller.OnReboot); + TryUpdateTask(ref serverPrimed, () => controller.OnPrime); + TryUpdateTask(ref activeServerStartup, () => controller.OnStartup); + + if (!sameController) lastController = controller; - } TryUpdateTask(ref activeLaunchParametersChanged, () => ActiveParametersUpdated.Task); TryUpdateTask( From 6bc7c635c5362edc98bd6e74c6779510cc6f6f95 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 00:31:20 -0400 Subject: [PATCH 040/717] Set `TgsEngineBuild` MSBuild property for the OD guys to work with --- .../Components/Engine/OpenDreamInstaller.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 3021238614a..3f300dff1c9 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -221,7 +221,7 @@ public override async ValueTask Install(ByondVersion version, string installPath await using (var buildProcess = processExecutor.LaunchProcess( dotnetPath, sourcePath, - "build -c Release", + "build -c Release /p:TgsEngineBuild=true", null, true, true)) From e706f4cd7e4bc9ebb2e82750cbf837fed79431d6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 00:54:22 -0400 Subject: [PATCH 041/717] Fix up all tests except the two main Live ones --- .../Models/Response/ByondResponse.cs | 12 +++++++++++- .../Rights/TestRights.cs | 2 +- .../Engine/TestPosixByondInstaller.cs | 2 +- .../Live/DummyGitHubService.cs | 10 ++++++---- .../Live/Instance/ByondTest.cs | 18 ++++++++++++++---- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs b/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs index 92d524728da..68703f4892c 100644 --- a/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs @@ -1,4 +1,6 @@ -using Tgstation.Server.Api.Models.Internal; +using System; + +using Tgstation.Server.Api.Models.Internal; namespace Tgstation.Server.Api.Models.Response { @@ -15,5 +17,13 @@ public ByondResponse(ByondVersion byondVersion) : base(byondVersion) { } + + /// + /// Initializes a new instance of the class. + /// + [Obsolete("JSON constructor", true)] + public ByondResponse() + { + } } } diff --git a/tests/Tgstation.Server.Api.Tests/Rights/TestRights.cs b/tests/Tgstation.Server.Api.Tests/Rights/TestRights.cs index e773f4da941..7589120c61d 100644 --- a/tests/Tgstation.Server.Api.Tests/Rights/TestRights.cs +++ b/tests/Tgstation.Server.Api.Tests/Rights/TestRights.cs @@ -40,7 +40,7 @@ public void TestAllPowerOfTwo() [TestMethod] public void TestAllRightsWorks() { - var allByondRights = ByondRights.CancelInstall | ByondRights.InstallOfficialOrChangeActiveByondVersion | ByondRights.ListInstalled | ByondRights.ReadActive | ByondRights.InstallCustomByondVersion | ByondRights.DeleteInstall; + var allByondRights = ByondRights.CancelInstall | ByondRights.InstallOfficialOrChangeActiveByondVersion | ByondRights.ListInstalled | ByondRights.ReadActive | ByondRights.InstallCustomByondVersion | ByondRights.DeleteInstall | ByondRights.InstallCustomOpenDreamVersion | ByondRights.InstallOfficialOrChangeActiveOpenDreamVersion; var automaticByondRights = RightsHelper.AllRights(); Assert.AreEqual(allByondRights, automaticByondRights); diff --git a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs index f98cb4dc1ac..c7f117fb7a9 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs @@ -68,7 +68,7 @@ public async Task TestDownload() var result = ExtractMemoryStreamFromInstallationData(await installer.DownloadVersion(new ByondVersion { Engine = EngineType.Byond, - Version = new Version(123, 252345), + Version = new Version(511, 1385), }, null, default)); Assert.IsTrue(ourArray.SequenceEqual(result.ToArray())); diff --git a/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs b/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs index 1b2e711ba68..ad7470d96f9 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs @@ -28,6 +28,8 @@ sealed class DummyGitHubService : IAuthenticatedGitHubService readonly ICryptographySuite cryptographySuite; readonly ILogger logger; + public static IGitHubClient RealTestClient; + public static async Task InitializeAndInject(CancellationToken cancellationToken) { var mockOptions = new Mock>(); @@ -37,12 +39,12 @@ public static async Task InitializeAndInject(CancellationToken cancellationToken }); var gitHubClientFactory = new GitHubClientFactory(new AssemblyInformationProvider(), Mock.Of>(), mockOptions.Object); - var gitHubClient = gitHubClientFactory.CreateClient(); + RealTestClient = gitHubClientFactory.CreateClient(); Release targetRelease; do { - var releases = await gitHubClient + var releases = await RealTestClient .Repository .Release .GetAll("tgstation", "tgstation-server") @@ -57,12 +59,12 @@ public static async Task InitializeAndInject(CancellationToken cancellationToken { TestLiveServer.TestUpdateVersion, targetRelease } }; - var testCommitTask = gitHubClient + var testCommitTask = RealTestClient .Repository .Commit .Get("Cyberboss", "common_core", "4b4926dfaf6295f19f8ae7abf03cb357dbb05b29") .WaitAsync(cancellationToken); - testPr = await gitHubClient + testPr = await RealTestClient .PullRequest .Get("Cyberboss", "common_core", 2) .WaitAsync(cancellationToken); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index 0aa49b4a53a..505a480f592 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -48,7 +48,7 @@ public ByondTest(IByondClient byondClient, IJobsClient jobsClient, IFileDownload this.byondClient = byondClient ?? throw new ArgumentNullException(nameof(byondClient)); this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); - this.testEngine = engineType; + testEngine = engineType; } public Task Run(CancellationToken cancellationToken, out Task firstInstall) @@ -82,7 +82,7 @@ public static async ValueTask GetEdgeVersion(EngineType engineType // linux map also needs updating in CI : new Dictionary() { - { "515.1612", "515.1611" } + { "515.1612", "515.1611" } }; if (missingVersionMap.TryGetValue(targetVersion, out var remappedVersion)) @@ -90,9 +90,19 @@ public static async ValueTask GetEdgeVersion(EngineType engineType Assert.IsTrue(ByondVersion.TryParse(targetVersion, out byondVersion), $"Bad version: {targetVersion}"); } + else if (engineType == EngineType.OpenDream) + { + var masterBranch = await DummyGitHubService.RealTestClient.Repository.Branch.Get("OpenDreamProject", "OpenDream", "master"); + + byondVersion = new ByondVersion + { + Engine = EngineType.OpenDream, + SourceCommittish = masterBranch.Commit.Sha, + }; + } else { - Assert.Fail($"Edge version retrieval for {engineType} not implemented!"); + Assert.Fail($"Unimplemented edge retrieval for engine type: {engineType}"); return null; } @@ -101,7 +111,7 @@ public static async ValueTask GetEdgeVersion(EngineType engineType async Task RunPartOne(CancellationToken cancellationToken) { - testVersion = await GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); + testVersion = await GetEdgeVersion(testEngine, fileDownloader, cancellationToken); await TestNoVersion(cancellationToken); await TestInstallNullVersion(cancellationToken); await TestInstallStable(cancellationToken); From a3e3733668a6a4036a1c10ab969c2d3417d80d72 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 03:39:57 -0400 Subject: [PATCH 042/717] Get most of the BYOND integration test working --- src/Tgstation.Server.Api/Models/ErrorCode.cs | 66 +++++++++---------- .../Models/Internal/ByondVersion.cs | 35 ++++++++-- .../Models/Response/ByondResponse.cs | 22 ++----- .../Components/Deployment/DreamMaker.cs | 14 ++-- .../Components/Engine/ByondInstallerBase.cs | 4 +- .../Engine/DelegatingEngineInstaller.cs | 4 +- .../Components/Engine/EngineInstallerBase.cs | 2 +- .../Components/Engine/EngineManager.cs | 27 +++++--- .../Components/Engine/IEngineInstaller.cs | 3 +- .../Components/Engine/OpenDreamInstaller.cs | 4 +- .../Components/Session/ISessionController.cs | 5 -- .../Components/Session/SessionController.cs | 16 ----- .../Session/SessionControllerFactory.cs | 2 +- .../Components/Watchdog/WatchdogBase.cs | 2 +- .../Controllers/ByondController.cs | 40 ++++++++--- .../Controllers/DreamDaemonController.cs | 2 +- .../System/PosixProcessFeatures.cs | 4 +- .../System/WindowsProcessFeatures.cs | 4 +- .../TestApiClient.cs | 18 +++-- .../Live/Instance/ByondTest.cs | 26 +++++--- .../Live/Instance/DeploymentTest.cs | 6 +- .../Live/Instance/WatchdogTest.cs | 22 ++++--- 22 files changed, 181 insertions(+), 147 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/ErrorCode.cs b/src/Tgstation.Server.Api/Models/ErrorCode.cs index fd9b92075d3..9261772de8f 100644 --- a/src/Tgstation.Server.Api/Models/ErrorCode.cs +++ b/src/Tgstation.Server.Api/Models/ErrorCode.cs @@ -228,10 +228,10 @@ public enum ErrorCode : uint RepoMismatchShaAndUpdate, /// - /// Could not delete a BYOND version due to it being set as the active version for the instance. + /// Could not delete a engine version due to it being set as the active version for the instance. /// - [Description("Could not delete BYOND version due to it being selected as the instance's active version.")] - ByondCannotDeleteActiveVersion, + [Description("Could not delete engine version due to it being selected as the instance's active version.")] + EngineCannotDeleteActiveVersion, /// /// contained duplicate s. @@ -312,28 +312,28 @@ public enum ErrorCode : uint ByondDirectXInstallFail, /// - /// Failed to download a given BYOND version. + /// Failed to download a given engine version. /// - [Description("Error downloading specified BYOND version!")] - ByondDownloadFail, + [Description("Error downloading specified engine version!")] + EngineDownloadFail, /// - /// Failed to lock BYOND executables. + /// Failed to lock engine executables. /// - [Description("Could not acquire lock on BYOND installation as none exist!")] - ByondNoVersionsInstalled, + [Description("Could not acquire lock on engine installation as none exist!")] + EngineNoVersionsInstalled, /// /// The DMAPI never validated itself /// - [Description("DreamDaemon did not validate the DMAPI! This can occur if your world is encountering runtime errors during startup.")] - DreamMakerNeverValidated, + [Description("The server did not validate the DMAPI! This can occur if your world is encountering runtime errors during startup.")] + DeploymentNeverValidated, /// /// The DMAPI sent an invalid validation request. /// [Description("The DMAPI sent an invalid validation request!")] - DreamMakerInvalidValidation, + DeploymentInvalidValidation, /// /// Tried to remove the last for a passwordless user. @@ -345,25 +345,25 @@ public enum ErrorCode : uint /// No .dme could be found for deployment. /// [Description("No .dme configured and could not automatically detect one!")] - DreamMakerNoDme, + DeploymentNoDme, /// /// The configured .dme could not be found. /// [Description("Could not load configured .dme!")] - DreamMakerMissingDme, + DeploymentMissingDme, /// - /// DreamMaker failed to compile. + /// Compiler failed to compile. /// - [Description("DreamMaker exited with a non-zero exit code!")] - DreamMakerExitCode, + [Description("Compiler exited with a non-zero exit code!")] + DeploymentExitCode, /// /// Deployment already in progress /// [Description("There is already a deployment operation in progress!")] - DreamMakerCompileJobInProgress, + DeploymentInProgress, /// /// Missing in database. @@ -420,15 +420,15 @@ public enum ErrorCode : uint WatchdogCompileJobCorrupted, /// - /// DreamDaemon exited before it finished starting. + /// Game server exited before it finished starting. /// - [Description("DreamDaemon failed to start!")] + [Description("Game server failed to start!")] WatchdogStartupFailed, /// - /// DreamDaemon timed-out before it finished starting. + /// Game server timed-out before it finished starting. /// - [Description("DreamDaemon failed to start within the configured timeout!")] + [Description("Game server failed to start within the configured timeout!")] WatchdogStartupTimeout, /// @@ -468,10 +468,10 @@ public enum ErrorCode : uint InstanceNotAtWhitelistedPath, /// - /// Attempted to make a DreamDaemon update with both and set. + /// Attempted to make a game server update with both and set. /// [Description("Cannot set both softShutdown and softReboot at once!")] - DreamDaemonDoubleSoft, + GameServerDoubleSoft, /// /// Attempted to launch DreamDaemon on a user account that had the BYOND pager running. @@ -480,10 +480,10 @@ public enum ErrorCode : uint DreamDaemonPagerRunning, /// - /// Could not bind to port we wanted to launch DreamDaemon on. + /// Could not bind to port we wanted to launch the game server on. /// - [Description("Could not bind to requested DreamDaemon port! Is there another service running on that port?")] - DreamDaemonPortInUse, + [Description("Could not bind to requested game server port! Is there another service running on that port?")] + GameServerPortInUse, /// /// Failed to post GitHub comments, or send TGS event. @@ -540,16 +540,16 @@ public enum ErrorCode : uint RepoTestMergeInvalidRemote, /// - /// Attempted to switch to a custom BYOND version that does not exist. + /// Attempted to switch to a custom engine version that does not exist. /// - [Description("Cannot switch to requested custom BYOND version as it is not currently installed.")] - ByondNonExistentCustomVersion, + [Description("Cannot switch to requested custom engine version as it is not currently installed.")] + EngineNonExistentCustomVersion, /// - /// Attempted to perform an operation that requires DreamDaemon (not the watchdog) to be running but it wasn't. + /// Attempted to perform an operation that requires server (not the watchdog) to be running but it wasn't. /// - [Description("Cannot perform this operation as DreamDaemon is not currently running!")] - DreamDaemonOffline, + [Description("Cannot perform this operation as the game server is not currently running!")] + GameServerOffline, /// /// Attempted to perform an instance operation with an offline instance. diff --git a/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs b/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs index 04e42bc7e41..f4617c8394a 100644 --- a/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs +++ b/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs @@ -1,7 +1,10 @@ using System; using System.ComponentModel.DataAnnotations; +using System.Diagnostics; using System.Linq; +using Tgstation.Server.Common.Extensions; + namespace Tgstation.Server.Api.Models.Internal { /// @@ -54,13 +57,30 @@ public static bool TryParse(string input, out ByondVersion? byondVersion) else engine = EngineType.Byond; - if (!Version.TryParse(splits.Last(), out var version)) - return false; + Version? version; + string? sha; + if (engine == EngineType.Byond) + { + if (!Version.TryParse(splits.Last(), out version)) + return false; + + sha = null; + } + else + { + Debug.Assert(engine == EngineType.OpenDream, "This does not support whatever ungodly new engine you've added"); + sha = splits.Last(); + if (sha.Length != Limits.MaximumCommitShaLength) + return false; + + version = null; + } byondVersion = new ByondVersion { Engine = engine, Version = version, + SourceCommittish = sha, }; return true; } @@ -91,8 +111,9 @@ public bool Equals(ByondVersion other) { // https://github.com/dotnet/roslyn-analyzers/issues/2875 #pragma warning disable CA1062 // Validate arguments of public methods - return other!.Version == Version - && other.Engine == Engine; + return other!.Version?.Semver() == Version?.Semver() + && other.Engine == Engine + && other.SourceCommittish == SourceCommittish; #pragma warning restore CA1062 // Validate arguments of public methods } @@ -101,7 +122,11 @@ public override bool Equals(object obj) => obj is ByondVersion other && Equals(other); /// - public override string ToString() => $"{(Engine != EngineType.Byond ? $"{Engine}-" : String.Empty)}{Version}"; // BYOND isn't display for backwards compatibility. SourceCommittish is not included + public override string ToString() + { + var isByond = Engine == EngineType.Byond; + return $"{(!isByond ? $"{Engine}-" : String.Empty)}{(isByond ? Version : SourceCommittish)}"; // BYOND isn't displayed for backwards compatibility + } /// public override int GetHashCode() => ToString().GetHashCode(); diff --git a/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs b/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs index 68703f4892c..0c3d19d4b6a 100644 --- a/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs @@ -1,29 +1,15 @@ -using System; - -using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Api.Models.Internal; namespace Tgstation.Server.Api.Models.Response { /// /// Represents an installed . /// - public sealed class ByondResponse : ByondVersion + public sealed class ByondResponse { /// - /// Initializes a new instance of the class. - /// - /// The to copy. - public ByondResponse(ByondVersion byondVersion) - : base(byondVersion) - { - } - - /// - /// Initializes a new instance of the class. + /// The represented . /// - [Obsolete("JSON constructor", true)] - public ByondResponse() - { - } + public ByondVersion? Version { get; set; } } } diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index cc7c03b0012..8b69627cf76 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -201,7 +201,7 @@ public async ValueTask DeploymentProcess( lock (deploymentLock) { if (deploying) - throw new JobException(ErrorCode.DreamMakerCompileJobInProgress); + throw new JobException(ErrorCode.DeploymentInProgress); deploying = true; } @@ -599,7 +599,7 @@ await eventConsumer.HandleEvent( var foundPaths = await ioManager.GetFilesWithExtension(resolvedOutputDirectory, DmeExtension, true, cancellationToken); var foundPath = foundPaths.FirstOrDefault(); if (foundPath == default) - throw new JobException(ErrorCode.DreamMakerNoDme); + throw new JobException(ErrorCode.DeploymentNoDme); job.DmeName = foundPath.Substring( resolvedOutputDirectory.Length + 1, foundPath.Length - resolvedOutputDirectory.Length - DmeExtension.Length - 2); // +1 for . in extension @@ -609,7 +609,7 @@ await eventConsumer.HandleEvent( var targetDme = ioManager.ConcatPath(outputDirectory, String.Join('.', job.DmeName, DmeExtension)); var targetDmeExists = await ioManager.FileExists(targetDme, cancellationToken); if (!targetDmeExists) - throw new JobException(ErrorCode.DreamMakerMissingDme); + throw new JobException(ErrorCode.DeploymentMissingDme); } logger.LogDebug("Selected {dmeName}.dme for compilation!", job.DmeName); @@ -642,7 +642,7 @@ await eventConsumer.HandleEvent( { if (!compileSuceeded) throw new JobException( - ErrorCode.DreamMakerExitCode, + ErrorCode.DeploymentExitCode, new JobException($"Compilation failed:{Environment.NewLine}{Environment.NewLine}{job.Output}")); progressReporter.StageName = "Validating DMAPI"; @@ -815,7 +815,7 @@ async ValueTask VerifyApi( validationStatus = controller.ApiValidationStatus; if (requireValidate && validationStatus == ApiValidationStatus.NeverValidated) - throw new JobException(ErrorCode.DreamMakerNeverValidated); + throw new JobException(ErrorCode.DeploymentNeverValidated); logger.LogTrace("API validation status: {validationStatus}", validationStatus); @@ -835,12 +835,12 @@ async ValueTask VerifyApi( return; case ApiValidationStatus.NeverValidated: if (requireValidate) - throw new JobException(ErrorCode.DreamMakerNeverValidated); + throw new JobException(ErrorCode.DeploymentNeverValidated); job.MinimumSecurityLevel = DreamDaemonSecurity.Ultrasafe; break; case ApiValidationStatus.BadValidationRequest: case ApiValidationStatus.Incompatible: - throw new JobException(ErrorCode.DreamMakerInvalidValidation); + throw new JobException(ErrorCode.DeploymentInvalidValidation); case ApiValidationStatus.UnaskedValidationRequest: default: throw new InvalidOperationException( diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index 6f2b0854e63..e3b18c50c7c 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -85,11 +85,11 @@ protected ByondInstallerBase(IIOManager ioManager, ILogger l } /// - public override IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask) + public override IEngineInstallation CreateInstallation(ByondVersion version, string path, Task installationTask) { CheckVersionValidity(version); - var binPathForVersion = IOManager.ConcatPath(version.ToString(), BinPath); + var binPathForVersion = IOManager.ConcatPath(path, BinPath); var supportsMapThreads = version.Version >= MapThreadsVersion; return new ByondInstallation( diff --git a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs index 19fde5df738..652a2e55fac 100644 --- a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs @@ -35,8 +35,8 @@ public Task CleanCache(CancellationToken cancellationToken) => Task.WhenAll(delegatedInstallers.Values.Select(installer => installer.CleanCache(cancellationToken))); /// - public IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask) - => DelegateCall(version, installer => installer.CreateInstallation(version, installationTask)); + public IEngineInstallation CreateInstallation(ByondVersion version, string path, Task installationTask) + => DelegateCall(version, installer => installer.CreateInstallation(version, path, installationTask)); /// public ValueTask DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs index 002819ff6cd..ded8a8c75f9 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs @@ -41,7 +41,7 @@ protected EngineInstallerBase(IIOManager ioManager, ILogger } /// - public abstract IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask); + public abstract IEngineInstallation CreateInstallation(ByondVersion version, string path, Task installationTask); /// public abstract Task CleanCache(CancellationToken cancellationToken); diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index dc1bb72577c..edd5be0deb0 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -169,7 +169,7 @@ public async ValueTask UseExecutables(ByondVersion requir logger.LogTrace( "Acquiring lock on BYOND version {version}...", requiredVersion?.ToString() ?? $"{ActiveVersion} (active)"); - var versionToUse = requiredVersion ?? ActiveVersion ?? throw new JobException(ErrorCode.ByondNoVersionsInstalled); + var versionToUse = requiredVersion ?? ActiveVersion ?? throw new JobException(ErrorCode.EngineNoVersionsInstalled); var installLock = await AssertAndLockVersion( null, versionToUse, @@ -201,7 +201,7 @@ public async ValueTask DeleteVersion(JobProgressReporter progressReporter, Byond logger.LogTrace("DeleteVersion {version}", version); if (version.Equals(ActiveVersion)) - throw new JobException(ErrorCode.ByondCannotDeleteActiveVersion); + throw new JobException(ErrorCode.EngineCannotDeleteActiveVersion); ReferenceCountingContainer container; lock (installedVersions) @@ -234,7 +234,7 @@ await Task.WhenAny( { // check again because it could have become the active version. if (version == ActiveVersion) - throw new JobException(ErrorCode.ByondCannotDeleteActiveVersion); + throw new JobException(ErrorCode.EngineCannotDeleteActiveVersion); bool proceed; lock (installedVersions) @@ -318,7 +318,7 @@ async ValueTask ReadVersion(string path) try { - AddInstallationContainer(version, Task.CompletedTask); + AddInstallationContainer(version, path, Task.CompletedTask); logger.LogDebug("Added detected BYOND version {versionKey}...", version); } catch (Exception ex) @@ -410,7 +410,10 @@ async ValueTask AssertAndLockVersion( if (!allowInstallation) throw new InvalidOperationException($"BYOND version {byondVersion} not installed!"); - installationContainer = AddInstallationContainer(byondVersion, ourTcs.Task); + installationContainer = AddInstallationContainer( + byondVersion, + ioManager.ResolvePath(byondVersion.ToString()), + ourTcs.Task); } installation = installationContainer.Instance; @@ -439,7 +442,7 @@ async ValueTask AssertAndLockVersion( else if (neededForLock) { if (byondEngine && byondVersion.Version.Build > 0) - throw new JobException(ErrorCode.ByondNonExistentCustomVersion); + throw new JobException(ErrorCode.EngineNonExistentCustomVersion); logger.LogWarning("The required BYOND version ({version}) is not readily available! We will have to install it.", byondVersion); } @@ -487,7 +490,10 @@ async ValueTask AssertAndLockVersion( /// A representing the running operation. async ValueTask InstallVersionFiles(JobProgressReporter progressReporter, ByondVersion version, Stream customVersionStream, CancellationToken cancellationToken) { - var installFullPath = ioManager.ResolvePath(version.ToString()); + var installFullPath = ioManager.ResolvePath( + version.Engine == EngineType.Byond + ? version.ToString() + : Guid.NewGuid().ToString()); // too much BS with OD i swear, we can't use the provided committish because it may expand later async ValueTask DirectoryCleanup() { await ioManager.DeleteDirectory(installFullPath, cancellationToken); @@ -545,7 +551,7 @@ await ioManager.WriteAllBytes( catch (HttpRequestException ex) { // since the user can easily provide non-exitent version numbers, we'll turn this into a JobException - throw new JobException(ErrorCode.ByondDownloadFail, ex); + throw new JobException(ErrorCode.EngineDownloadFail, ex); } catch (OperationCanceledException) { @@ -562,11 +568,12 @@ await ioManager.WriteAllBytes( /// Create and add a new to . /// /// The being added. + /// The path to the installation. /// The representing the installation process. /// The new . - ReferenceCountingContainer AddInstallationContainer(ByondVersion version, Task installationTask) + ReferenceCountingContainer AddInstallationContainer(ByondVersion version, string installPath, Task installationTask) { - var installation = engineInstaller.CreateInstallation(version, installationTask); + var installation = engineInstaller.CreateInstallation(version, installPath, installationTask); var installationContainer = new ReferenceCountingContainer(installation); diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs index 346599843e3..e7ef6a41502 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs @@ -15,9 +15,10 @@ interface IEngineInstaller /// Creates an for a given . /// /// The of the installation. + /// The path to the installation. /// The representing the installation process for the installation. /// The . - IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask); + IEngineInstallation CreateInstallation(ByondVersion version, string path, Task installationTask); /// /// Download a given engine . diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 3f300dff1c9..0436a5eec00 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -84,10 +84,10 @@ public OpenDreamInstaller( public override Task CleanCache(CancellationToken cancellationToken) => Task.CompletedTask; /// - public override IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask) + public override IEngineInstallation CreateInstallation(ByondVersion version, string path, Task installationTask) { CheckVersionValidity(version); - var binPathForVersion = IOManager.ConcatPath(version.ToString(), InstallationBinDirectory); + var binPathForVersion = IOManager.ConcatPath(path, InstallationBinDirectory); var exeExtension = platformIdentifier.IsWindows ? ".exe" diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs index ba894c941c9..3082a2d2533 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs @@ -49,11 +49,6 @@ interface ISessionController : IProcessBase, IRenameNotifyee, IAsyncDisposable /// ReattachInformation ReattachInformation { get; } - /// - /// If the port should be rotated off when the world reboots. - /// - bool ClosePortOnReboot { get; set; } - /// /// If the is currently processing a bridge request from TgsReboot(). /// diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 3802387b615..df2971588dd 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -61,9 +61,6 @@ public ApiValidationStatus ApiValidationStatus /// public Version DMApiVersion { get; private set; } - /// - public bool ClosePortOnReboot { get; set; } - /// public bool TerminationWasRequested { get; private set; } @@ -201,11 +198,6 @@ async Task Wrap() /// ApiValidationStatus apiValidationStatus; - /// - /// If we know DreamDaemon currently has it's port closed. - /// - bool portClosedForReboot; - /// /// If the has been disposed. /// @@ -265,7 +257,6 @@ public SessionController( this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); - portClosedForReboot = false; disposed = false; apiValidationStatus = ApiValidationStatus.NeverValidated; released = false; @@ -720,13 +711,6 @@ async ValueTask ProcessBridgeCommand(BridgeParameters parameters Interlocked.Increment(ref rebootBridgeRequestsProcessing); try { - if (ClosePortOnReboot) - { - chatTrackingContext.Active = false; - response.NewPort = 0; - portClosedForReboot = true; - } - Interlocked.Exchange(ref rebootTcs, new TaskCompletionSource()).SetResult(); await RebootGate.WaitAsync(cancellationToken); } diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 6e529714f78..c2dba13e8c3 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -139,7 +139,7 @@ void PortBindTest(ushort port) } catch (SocketException ex) when (ex.SocketErrorCode == SocketError.AddressAlreadyInUse) { - throw new JobException(ErrorCode.DreamDaemonPortInUse, ex); + throw new JobException(ErrorCode.GameServerPortInUse, ex); } } diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index 522424daddd..b7b72a31bd5 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -446,7 +446,7 @@ public async ValueTask CreateDump(CancellationToken cancellationToken) var session = GetActiveController(); if (session?.Lifetime.IsCompleted != false) - throw new JobException(ErrorCode.DreamDaemonOffline); + throw new JobException(ErrorCode.GameServerOffline); Logger.LogInformation("Dumping session to {dumpFileName}...", dumpFileName); await session.CreateDump(dumpFileName, cancellationToken); diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index b57df144fc0..f9cfa3c2136 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Tgstation.Server.Api; using Tgstation.Server.Api.Models; @@ -13,7 +14,9 @@ using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Api.Rights; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components; +using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.Jobs; @@ -39,6 +42,11 @@ public sealed class ByondController : InstanceRequiredController /// readonly IFileTransferTicketProvider fileTransferService; + /// + /// The for the . + /// + readonly GeneralConfiguration generalConfiguration; + /// /// Remove the from a given if present. /// @@ -55,13 +63,15 @@ public sealed class ByondController : InstanceRequiredController /// The for the . /// The value of . /// The value of . + /// The containing the value of . public ByondController( IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ILogger logger, IInstanceManager instanceManager, IJobManager jobManager, - IFileTransferTicketProvider fileTransferService) + IFileTransferTicketProvider fileTransferService, + IOptions generalConfigurationOptions) : base( databaseContext, authenticationContextFactory, @@ -70,6 +80,7 @@ public ByondController( { this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); this.fileTransferService = fileTransferService ?? throw new ArgumentNullException(nameof(fileTransferService)); + generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } /// @@ -85,11 +96,11 @@ public ByondController( public ValueTask Read() => WithComponentInstance(instance => ValueTask.FromResult( - instance.EngineManager.ActiveVersion != null - ? Json( - new ByondResponse( - instance.EngineManager.ActiveVersion)) - : Conflict(new ErrorMessageResponse(ErrorCode.ResourceNotPresent)))); + Json( + new ByondResponse + { + Version = instance.EngineManager.ActiveVersion, + }))); /// /// Lists installed s. @@ -110,7 +121,10 @@ public ValueTask List([FromQuery] int? page, [FromQuery] int? pag instance .EngineManager .InstalledVersions - .Select(x => new ByondResponse(x)) + .Select(x => new ByondResponse + { + Version = x, + }) .AsQueryable() .OrderBy(x => x.Version))), null, @@ -185,7 +199,7 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode if (!versionAlreadyInstalled) { if (model.Version.Build > 0) - return BadRequest(new ErrorMessageResponse(ErrorCode.ByondNonExistentCustomVersion)); + return BadRequest(new ErrorMessageResponse(ErrorCode.EngineNonExistentCustomVersion)); Logger.LogInformation( "User ID {userId} installing {engineType} version {newByondVersion}{sourceCommittish} on instance ID {instanceId}", @@ -287,7 +301,7 @@ public async ValueTask Delete([FromBody] ByondVersionDeleteReques if (model.Equals(byondManager.ActiveVersion)) return ValueTask.FromResult( - Conflict(new ErrorMessageResponse(ErrorCode.ByondCannotDeleteActiveVersion))); + Conflict(new ErrorMessageResponse(ErrorCode.EngineCannotDeleteActiveVersion))); var versionNotInstalled = !byondManager.InstalledVersions.Any(x => x.Equals(model)); @@ -336,6 +350,9 @@ BadRequestObjectResult ValidateByondVersion(ByondVersion version) { ArgumentNullException.ThrowIfNull(version); + if (!version.Engine.HasValue) + return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); + var isByond = version.Engine.Value == EngineType.Byond; if ((isByond && (version.Version == null @@ -348,6 +365,11 @@ BadRequestObjectResult ValidateByondVersion(ByondVersion version) if (isByond) version.Version = NormalizeByondVersion(version.Version); + else if (version.Engine.Value == EngineType.OpenDream && version.Version != null) + { + version.SourceCommittish = String.Concat(generalConfiguration.OpenDreamGitTagPrefix, version.Version.Semver()); + version.Version = null; + } return null; } diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index f4613f81d00..6cc1f27cabb 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -162,7 +162,7 @@ public async ValueTask Update([FromBody] DreamDaemonRequest model ArgumentNullException.ThrowIfNull(model); if (model.SoftShutdown == true && model.SoftRestart == true) - return BadRequest(new ErrorMessageResponse(ErrorCode.DreamDaemonDoubleSoft)); + return BadRequest(new ErrorMessageResponse(ErrorCode.GameServerDoubleSoft)); // alias for changing DD settings var current = await DatabaseContext diff --git a/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs b/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs index 0e1dab1d3cf..b45c845fa4b 100644 --- a/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs +++ b/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs @@ -77,13 +77,13 @@ public async ValueTask CreateDump(global::System.Diagnostics.Process process, st try { if (process.HasExited) - throw new JobException(ErrorCode.DreamDaemonOffline); + throw new JobException(ErrorCode.GameServerOffline); pid = process.Id; } catch (InvalidOperationException ex) { - throw new JobException(ErrorCode.DreamDaemonOffline, ex); + throw new JobException(ErrorCode.GameServerOffline, ex); } string output; diff --git a/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs b/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs index efbb029e0af..41789aec8cc 100644 --- a/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs +++ b/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs @@ -125,11 +125,11 @@ public async ValueTask CreateDump(global::System.Diagnostics.Process process, st try { if (process.HasExited) - throw new JobException(ErrorCode.DreamDaemonOffline); + throw new JobException(ErrorCode.GameServerOffline); } catch (InvalidOperationException ex) { - throw new JobException(ErrorCode.DreamDaemonOffline, ex); + throw new JobException(ErrorCode.GameServerOffline, ex); } await using var fileStream = new FileStream(outputFile, FileMode.CreateNew); diff --git a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs index 3027f9ac45a..74537b9dac5 100644 --- a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs +++ b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs @@ -24,12 +24,14 @@ public sealed class TestApiClient [TestMethod] public async Task TestDeserializingByondModelsWork() { - var sample = new ByondResponse( - new ByondVersion + var sample = new ByondResponse + { + Version = new ByondVersion { Engine = EngineType.Byond, Version = new Version(511, 1385, 0) - }); + } + }; var sampleJson = JsonConvert.SerializeObject(sample, new JsonSerializerSettings { @@ -49,18 +51,20 @@ public async Task TestDeserializingByondModelsWork() var result = await client.Read(Routes.Byond, default); Assert.AreEqual(sample.Version, result.Version); - Assert.AreEqual(0, result.Version.Build); + Assert.AreEqual(0, result.Version.Version.Build); } [TestMethod] public async Task TestUnrecognizedResponse() { - var sample = new ByondResponse( - new ByondVersion + var sample = new ByondResponse + { + Version = new ByondVersion { Engine = EngineType.Byond, Version = new Version(511, 1385) - }); + } + }; var fakeJson = "asdfasd <>F#(*)U*#JLI"; diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index 505a480f592..2f094229e56 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -148,7 +148,8 @@ async Task TestDeletes(CancellationToken cancellationToken) var nonExistentUninstallResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( new ByondVersionDeleteRequest { - Version = new(509, 1000) + Version = new(509, 1000), + Engine = testEngine, }, cancellationToken), ErrorCode.ResourceNotPresent); @@ -168,7 +169,7 @@ async Task TestDeletes(CancellationToken cancellationToken) Engine = testVersion.Engine, SourceCommittish = testVersion.SourceCommittish, }, - cancellationToken), ErrorCode.ByondCannotDeleteActiveVersion); + cancellationToken), ErrorCode.EngineCannotDeleteActiveVersion); await badBecauseActiveResponseTask; @@ -187,7 +188,7 @@ async Task TestDeletes(CancellationToken cancellationToken) var newVersions = await byondClient.InstalledVersions(null, cancellationToken); Assert.IsNotNull(newVersions); Assert.AreEqual(1, newVersions.Count); - Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 1), newVersions[0].Version); + Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 1), newVersions[0].Version.Version); } async Task TestInstallFakeVersion(CancellationToken cancellationToken) @@ -196,9 +197,14 @@ async Task TestInstallFakeVersion(CancellationToken cancellationToken) { Version = new Version(5011, 1385) }; + + await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(newModel, null, cancellationToken), ErrorCode.ModelValidationFailure); + + newModel.Engine = testEngine; + var test = await byondClient.SetActiveVersion(newModel, null, cancellationToken); Assert.IsNotNull(test.InstallJob); - await WaitForJob(test.InstallJob, 60, true, ErrorCode.ByondDownloadFail, cancellationToken); + await WaitForJob(test.InstallJob, 60, true, ErrorCode.EngineDownloadFail, cancellationToken); } async Task TestInstallStable(CancellationToken cancellationToken) @@ -213,7 +219,7 @@ async Task TestInstallStable(CancellationToken cancellationToken) Assert.IsNotNull(test.InstallJob); await WaitForJob(test.InstallJob, 180, false, null, cancellationToken); var currentShit = await byondClient.ActiveVersion(cancellationToken); - Assert.AreEqual(newModel.Version.Semver(), currentShit.Version); + Assert.AreEqual(newModel.Version.Semver(), currentShit.Version.Version); var dreamMaker = "DreamMaker"; if (new PlatformIdentifier().IsWindows) @@ -297,7 +303,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) await WaitForJob(test2.InstallJob, 30, false, null, cancellationToken); var newSettings = await byondClient.ActiveVersion(cancellationToken); - Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 2), newSettings.Version); + Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 2), newSettings.Version.Version); // test a few switches var installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest @@ -309,12 +315,14 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) Assert.IsNull(installResponse.InstallJob); await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(new ByondVersionRequest { - Version = new Version(testVersion.Version.Major, testVersion.Version.Minor, 3) - }, null, cancellationToken), ErrorCode.ByondNonExistentCustomVersion); + Version = new Version(testVersion.Version.Major, testVersion.Version.Minor, 3), + Engine = testEngine, + }, null, cancellationToken), ErrorCode.EngineNonExistentCustomVersion); installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest { - Version = new Version(testVersion.Version.Major, testVersion.Version.Minor, 1) + Version = new Version(testVersion.Version.Major, testVersion.Version.Minor, 1), + Engine = testEngine, }, null, cancellationToken); Assert.IsNull(installResponse.InstallJob); } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs index 1ecf82aa9de..3861634aa26 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs @@ -149,7 +149,7 @@ async Task CompileAfterByondInstall() var deployJobTask = CompileAfterByondInstall(); var deployJob = await deployJobTask; - var deploymentJobWaitTask = WaitForJob(deployJob, 40, true, ErrorCode.DreamMakerNeverValidated, cancellationToken); + var deploymentJobWaitTask = WaitForJob(deployJob, 40, true, ErrorCode.DeploymentNeverValidated, cancellationToken); await CheckDreamDaemonPriority(deploymentJobWaitTask, cancellationToken); @@ -174,7 +174,7 @@ async Task CompileAfterByondInstall() Assert.AreEqual(FailProject, updated.ProjectName); deployJob = await dreamMakerClient.Compile(cancellationToken); - await WaitForJob(deployJob, 40, true, ErrorCode.DreamMakerExitCode, cancellationToken); + await WaitForJob(deployJob, 40, true, ErrorCode.DeploymentExitCode, cancellationToken); await dreamMakerClient.Update(new DreamMakerRequest { @@ -182,7 +182,7 @@ await dreamMakerClient.Update(new DreamMakerRequest }, cancellationToken); deployJob = await dreamMakerClient.Compile(cancellationToken); - await WaitForJob(deployJob, 40, true, ErrorCode.DreamMakerMissingDme, cancellationToken); + await WaitForJob(deployJob, 40, true, ErrorCode.DeploymentMissingDme, cancellationToken); // check that we can change the visibility diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 2726b4a5761..f299c3c32f6 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -94,10 +94,10 @@ async Task CheckByondVersions() Assert.AreEqual(1, list.Count); var byondVersion = list[0]; - Assert.AreEqual(1, byondVersion.Version.Build); - Assert.AreEqual(testVersion.Version.Major, byondVersion.Version.Major); - Assert.AreEqual(testVersion.Version.Minor, byondVersion.Version.Minor); - Assert.AreEqual(testVersion.Engine, byondVersion.Engine); + Assert.AreEqual(1, byondVersion.Version.Version.Build); + Assert.AreEqual(testVersion.Version.Major, byondVersion.Version.Version.Major); + Assert.AreEqual(testVersion.Version.Minor, byondVersion.Version.Version.Minor); + Assert.AreEqual(testVersion.Engine, byondVersion.Version.Engine); } await Task.WhenAll( @@ -115,7 +115,7 @@ await Task.WhenAll( { SoftShutdown = true, SoftRestart = true - }, cancellationToken), ErrorCode.DreamDaemonDoubleSoft).AsTask(), + }, cancellationToken), ErrorCode.GameServerDoubleSoft).AsTask(), ApiAssert.ThrowsException(() => instanceClient.DreamDaemon.Update(new DreamDaemonRequest { Port = 0 @@ -235,7 +235,7 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo var testCustomVersion = new Version(testVersion.Version.Major, testVersion.Version.Minor, 1); var currentByond = await instanceClient.Byond.ActiveVersion(cancellationToken); Assert.IsNotNull(currentByond); - Assert.AreEqual(testVersion.Version.Semver(), currentByond.Version); + Assert.AreEqual(testVersion.Version.Semver(), currentByond.Version.Version); // Change the active version and check we get delayed while deleting the old one because the watchdog is using it var setActiveResponse = await instanceClient.Byond.SetActiveVersion( @@ -254,6 +254,7 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo { Version = testVersion.Version, SourceCommittish = testVersion.SourceCommittish, + Engine = testVersion.Engine, }, cancellationToken); @@ -278,7 +279,7 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo Assert.IsNotNull(setActiveResponse); Assert.IsNull(setActiveResponse.InstallJob); - await WaitForJob(deleteJob, 5, true, ErrorCode.ByondCannotDeleteActiveVersion, cancellationToken); + await WaitForJob(deleteJob, 5, true, ErrorCode.EngineCannotDeleteActiveVersion, cancellationToken); // finally, queue the last delete job which should complete when the watchdog restarts with a newly deployed .dmb // queue the byond change followed by the deployment for that first @@ -286,6 +287,7 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo new ByondVersionRequest { Version = testCustomVersion, + Engine = testVersion.Engine, }, null, cancellationToken); @@ -372,7 +374,7 @@ async Task DumpTests(CancellationToken cancellationToken) await WaitForJob(restartJob, 20, false, null, cancellationToken); } - Assert.IsTrue(job.ErrorCode == ErrorCode.DreamDaemonOffline || job.ErrorCode == ErrorCode.GCoreFailure, $"{job.ErrorCode}: {job.ExceptionDetails}"); + Assert.IsTrue(job.ErrorCode == ErrorCode.GameServerOffline || job.ErrorCode == ErrorCode.GCoreFailure, $"{job.ErrorCode}: {job.ExceptionDetails}"); await Task.Delay(TimeSpan.FromSeconds(20), cancellationToken); @@ -447,7 +449,7 @@ async Task RunBasicTest(CancellationToken cancellationToken) // Don't use StartDD here startJob = await instanceClient.DreamDaemon.Start(cancellationToken); - await WaitForJob(startJob, 40, true, ErrorCode.DreamDaemonPortInUse, cancellationToken); + await WaitForJob(startJob, 40, true, ErrorCode.GameServerPortInUse, cancellationToken); } startJob = await StartDD(cancellationToken); @@ -962,7 +964,7 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken var versionToInstall = testVersion; var currentByondVersion = await instanceClient.Byond.ActiveVersion(cancellationToken); - Assert.AreNotEqual(versionToInstall, currentByondVersion); + Assert.AreNotEqual(versionToInstall, currentByondVersion.Version); var initialStatus = await instanceClient.DreamDaemon.Read(cancellationToken); From a6907d360dfc646b987dfdca252ffbb1ada69deb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 03:45:36 -0400 Subject: [PATCH 043/717] Missed a spot --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index f299c3c32f6..309f0d19635 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -242,6 +242,7 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo new ByondVersionRequest { Version = testCustomVersion, + Engine = testVersion.Engine, }, null, cancellationToken); From 59cefa9f4f558812be25d0107949419570d59626 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 11:37:09 -0400 Subject: [PATCH 044/717] Fix a VS message --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 309f0d19635..a0316338de4 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -514,7 +514,7 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke Assert.Fail($"Incorrect number of DD processes: {ddProcs.Count}"); using var ddProc = ddProcs.Single(); - IProcessExecutor executor = null; + ProcessExecutor executor = null; executor = new ProcessExecutor( RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? new WindowsProcessFeatures(Mock.Of>()) From 22f9a3bc61e63f528e655598ae5cc77e31ef41ed Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 12:17:32 -0400 Subject: [PATCH 045/717] Rework OD test to be alongside main tests Fix a bunch of VS messages too --- .../Live/Instance/ByondTest.cs | 26 +++----- .../Live/Instance/InstanceTest.cs | 45 ++++++-------- .../Live/TestLiveServer.cs | 60 +++++++++++-------- 3 files changed, 61 insertions(+), 70 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index b0ba700db50..ae560e1e27d 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -26,30 +26,21 @@ namespace Tgstation.Server.Tests.Live.Instance { - sealed class ByondTest : JobsRequiredTest + sealed class ByondTest(IByondClient byondClient, IJobsClient jobsClient, IFileDownloader fileDownloader, Api.Models.Instance metadata, EngineType engineType) : JobsRequiredTest(jobsClient) { - readonly IByondClient byondClient; - readonly IFileDownloader fileDownloader; + readonly IByondClient byondClient = byondClient ?? throw new ArgumentNullException(nameof(byondClient)); + readonly IFileDownloader fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); - readonly Api.Models.Instance metadata; + readonly Api.Models.Instance metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); - static Dictionary edgeVersions = new Dictionary + static readonly Dictionary edgeVersions = new () { { EngineType.Byond, null }, { EngineType.OpenDream, null } }; ByondVersion testVersion; - EngineType testEngine; - - public ByondTest(IByondClient byondClient, IJobsClient jobsClient, IFileDownloader fileDownloader, Api.Models.Instance metadata, EngineType engineType) - : base(jobsClient) - { - this.byondClient = byondClient ?? throw new ArgumentNullException(nameof(byondClient)); - this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); - this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); - testEngine = engineType; - } + readonly EngineType testEngine = engineType; public Task Run(CancellationToken cancellationToken, out Task firstInstall) { @@ -76,9 +67,7 @@ public static async ValueTask GetEdgeVersion(EngineType engineType var targetVersion = splits.Last(); var badVersionMap = new PlatformIdentifier().IsWindows - ? new Dictionary() - { - } + ? [] // linux map also needs updating in CI : new Dictionary() { @@ -108,6 +97,7 @@ public static async ValueTask GetEdgeVersion(EngineType engineType return null; } + global::System.Console.WriteLine($"Edge {engineType} version evalutated to {byondVersion}"); return edgeVersions[engineType] = byondVersion; } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 7dd1e992533..ae100a465ac 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -23,20 +24,12 @@ namespace Tgstation.Server.Tests.Live.Instance { - sealed class InstanceTest + sealed class InstanceTest(IInstanceManagerClient instanceManagerClient, IFileDownloader fileDownloader, InstanceManager instanceManager, ushort serverPort) { - readonly IInstanceManagerClient instanceManagerClient; - readonly IFileDownloader fileDownloader; - readonly InstanceManager instanceManager; - readonly ushort serverPort; - - public InstanceTest(IInstanceManagerClient instanceManagerClient, IFileDownloader fileDownloader, InstanceManager instanceManager, ushort serverPort) - { - this.instanceManagerClient = instanceManagerClient ?? throw new ArgumentNullException(nameof(instanceManagerClient)); - this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); - this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager)); - this.serverPort = serverPort; - } + readonly IInstanceManagerClient instanceManagerClient = instanceManagerClient ?? throw new ArgumentNullException(nameof(instanceManagerClient)); + readonly IFileDownloader fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); + readonly InstanceManager instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager)); + readonly ushort serverPort = serverPort; public async Task RunTests( IInstanceClient instanceClient, @@ -44,10 +37,9 @@ public async Task RunTests( ushort ddPort, bool highPrioDD, bool lowPrioDeployment, - EngineType engineType, CancellationToken cancellationToken) { - var byondTest = new ByondTest(instanceClient.Byond, instanceClient.Jobs, fileDownloader, instanceClient.Metadata, engineType); + var byondTest = new ByondTest(instanceClient.Byond, instanceClient.Jobs, fileDownloader, instanceClient.Metadata, EngineType.Byond); var chatTest = new ChatTest(instanceClient.ChatBots, instanceManagerClient, instanceClient.Jobs, instanceClient.Metadata); var configTest = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata); var repoTest = new RepositoryTest(instanceClient.Repository, instanceClient.Jobs); @@ -68,30 +60,29 @@ public async Task RunTests( await byondTask; await new WatchdogTest( - await ByondTest.GetEdgeVersion(engineType, fileDownloader, cancellationToken), instanceClient, instanceManager, serverPort, highPrioDD, ddPort).Run(cancellationToken); + await ByondTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken), instanceClient, instanceManager, serverPort, highPrioDD, ddPort).Run(cancellationToken); } public async Task RunCompatTests( - Version compatByondVersion, + ByondVersion compatVersion, IInstanceClient instanceClient, ushort dmPort, ushort ddPort, bool highPrioDD, CancellationToken cancellationToken) { - var compatVersion = new ByondVersion - { - Engine = EngineType.Byond, - Version = compatByondVersion, - }; - + if (compatVersion.Engine != EngineType.Byond) +#if !DEBUG + Assert.Fail("Compat test for OD not release ready!"); +#else + return; +#endif System.Console.WriteLine($"COMPAT TEST START: {compatVersion}"); const string Origin = "https://github.com/Cyberboss/common_core"; var cloneRequest = instanceClient.Repository.Clone(new RepositoryCreateRequest { Origin = new Uri(Origin), - }, cancellationToken); - + }, cancellationToken).AsTask(); var dmUpdateRequest = instanceClient.DreamMaker.Update(new DreamMakerRequest { @@ -122,7 +113,7 @@ public async Task RunCompatTests( ChannelLimit = 10, Channels = new List { - new ChatChannel + new () { ChannelData = channelIdStr, Tag = "some_tag", @@ -180,7 +171,7 @@ await Task.WhenAll( jrt.WaitForJob(cloneRequest.Result.ActiveJob, 60, false, null, cancellationToken), jrt.WaitForJob(theJobWeWant, 30, false, null, cancellationToken), dmUpdateRequest.AsTask(), - cloneRequest.AsTask()); + cloneRequest); var configSetupTask = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata).SetupDMApiTests(cancellationToken); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 3b0c80abdaf..2ee8cde690a 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -56,7 +56,7 @@ public sealed class TestLiveServer static readonly ushort compatDMPort = FreeTcpPort(mainDDPort, mainDMPort); static readonly ushort compatDDPort = FreeTcpPort(mainDDPort, mainDMPort, compatDMPort); - readonly IServerClientFactory clientFactory = new ServerClientFactory(new ProductHeaderValue(Assembly.GetExecutingAssembly().GetName().Name, Assembly.GetExecutingAssembly().GetName().Version.ToString())); + readonly ServerClientFactory clientFactory = new (new ProductHeaderValue(Assembly.GetExecutingAssembly().GetName().Name, Assembly.GetExecutingAssembly().GetName().Version.ToString())); public static List GetDDProcessesOnPort(ushort? port) { @@ -956,12 +956,7 @@ await Task.WhenAny( } [TestMethod] - public Task TestStandardTgsOperation() => TestStandardTgsOperation(EngineType.Byond); - - [TestMethod] - public Task TestOpenDreamTgsOperation() => TestStandardTgsOperation(EngineType.OpenDream); - - async Task TestStandardTgsOperation(EngineType engineType) + public async Task TestStandardTgsOperation() { using(var currentProcess = System.Diagnostics.Process.GetCurrentProcess()) { @@ -986,7 +981,7 @@ async Task TestStandardTgsOperation(EngineType engineType) ServiceCollectionExtensions.UseAdditionalLoggerProvider(); var failureTask = HardFailLoggerProvider.FailureSource; - var internalTask = TestTgsInternal(engineType, hardCancellationToken); + var internalTask = TestTgsInternal(hardCancellationToken); await Task.WhenAny( internalTask, failureTask); @@ -1018,7 +1013,7 @@ await Task.WhenAny( await internalTask; } - async Task TestTgsInternal(EngineType engineType, CancellationToken hardCancellationToken) + async Task TestTgsInternal(CancellationToken hardCancellationToken) { var discordConnectionString = Environment.GetEnvironmentVariable("TGS_TEST_DISCORD_TOKEN"); var ircConnectionString = Environment.GetEnvironmentVariable("TGS_TEST_IRC_CONNECTION_STRING"); @@ -1046,19 +1041,15 @@ async Task TestTgsInternal(EngineType engineType, CancellationToken hardCancella Assert.IsTrue(new IrcConnectionStringBuilder(ircConnectionString).Valid); } - if (engineType == EngineType.Byond) + var procs = System.Diagnostics.Process.GetProcessesByName("byond"); + if (procs.Length != 0) { - var procs = System.Diagnostics.Process.GetProcessesByName("byond"); - if (procs.Any()) - { - foreach (var proc in procs) - proc.Dispose(); + foreach (var proc in procs) + proc.Dispose(); - // Inconclusive and not fail because we don't want to unexpectedly kill a dev's BYOND.exe - Assert.Inconclusive("Cannot run server test because DreamDaemon will not start headless while the BYOND pager is running!"); - } + // Inconclusive and not fail because we don't want to unexpectedly kill a dev's BYOND.exe + Assert.Inconclusive("Cannot run server test because DreamDaemon will not start headless while the BYOND pager is running!"); } - using var server = new LiveTestingServer(null, true); using var serverCts = CancellationTokenSource.CreateLinkedTokenSource(hardCancellationToken); @@ -1127,12 +1118,16 @@ async Task FailFast(Task task) async Task RunInstanceTests() { // Some earlier linux BYOND versions have a critical bug where replacing the directory in non-basic watchdogs causes the DreamDaemon cwd to change - var canRunCompatTests = engineType == EngineType.Byond && new PlatformIdentifier().IsWindows; + var canRunCompatTests = new PlatformIdentifier().IsWindows; var compatTests = canRunCompatTests ? FailFast( instanceTest .RunCompatTests( - new Version(510, 1346), + new ByondVersion + { + Engine = EngineType.Byond, + Version = new Version(510, 1346) + }, adminClient.Instances.CreateClient(compatInstance), compatDMPort, compatDDPort, @@ -1143,6 +1138,21 @@ async Task RunInstanceTests() if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization await compatTests; + var odCompatTests = canRunCompatTests + ? FailFast( + instanceTest + .RunCompatTests( + await ByondTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellationToken), + adminClient.Instances.CreateClient(compatInstance), + compatDMPort, + compatDDPort, + server.HighPriorityDreamDaemon, + cancellationToken)) + : Task.CompletedTask; + + if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization + await odCompatTests; + await FailFast( instanceTest .RunTests( @@ -1151,10 +1161,10 @@ await FailFast( mainDDPort, server.HighPriorityDreamDaemon, server.LowPriorityDeployments, - engineType, cancellationToken)); await compatTests; + await odCompatTests; } var instanceTests = RunInstanceTests(); @@ -1221,7 +1231,7 @@ await FailFast( var instanceClient = adminClient.Instances.CreateClient(instance); var jobs = await instanceClient.Jobs.ListActive(null, cancellationToken); - if (!jobs.Any()) + if (jobs.Count == 0) { var entities = await instanceClient.Jobs.List(null, cancellationToken); var getTasks = entities @@ -1293,7 +1303,7 @@ await FailFast( async Task WaitForInitialJobs(IInstanceClient instanceClient) { var jobs = await instanceClient.Jobs.ListActive(null, cancellationToken); - if (!jobs.Any()) + if (jobs.Count == 0) { var entities = await instanceClient.Jobs.List(null, cancellationToken); var getTasks = entities @@ -1318,7 +1328,7 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) preStartupTime = DateTimeOffset.UtcNow; serverTask = server.Run(cancellationToken).AsTask(); long expectedCompileJobId, expectedStaged; - var edgeVersion = await ByondTest.GetEdgeVersion(engineType, fileDownloader, cancellationToken); + var edgeVersion = await ByondTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); using (var adminClient = await CreateAdminClient(server.Url, cancellationToken)) { var instanceClient = adminClient.Instances.CreateClient(instance); From 46ed0ab4c2bd801d76f787829cf2471e6994d7a9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 12:19:24 -0400 Subject: [PATCH 046/717] Fix bad assumption about DummyGitHubService How was this working previously? --- .../Live/DummyGitHubServiceFactory.cs | 6 +++--- .../Live/Instance/ByondTest.cs | 2 +- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 2 +- ...ummyGitHubService.cs => TestingGitHubService.cs} | 13 ++++++++----- 4 files changed, 13 insertions(+), 10 deletions(-) rename tests/Tgstation.Server.Tests/Live/{DummyGitHubService.cs => TestingGitHubService.cs} (93%) diff --git a/tests/Tgstation.Server.Tests/Live/DummyGitHubServiceFactory.cs b/tests/Tgstation.Server.Tests/Live/DummyGitHubServiceFactory.cs index 7df388085ea..2f657577820 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyGitHubServiceFactory.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyGitHubServiceFactory.cs @@ -10,9 +10,9 @@ namespace Tgstation.Server.Tests.Live sealed class DummyGitHubServiceFactory : IGitHubServiceFactory { readonly ICryptographySuite cryptographySuite; - readonly ILogger logger; + readonly ILogger logger; - public DummyGitHubServiceFactory(ICryptographySuite cryptographySuite, ILogger logger) + public DummyGitHubServiceFactory(ICryptographySuite cryptographySuite, ILogger logger) { this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -27,6 +27,6 @@ public IAuthenticatedGitHubService CreateService(string accessToken) return CreateDummyService(); } - DummyGitHubService CreateDummyService() => new DummyGitHubService(cryptographySuite, logger); + TestingGitHubService CreateDummyService() => new TestingGitHubService(cryptographySuite, logger); } } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index ae560e1e27d..672d2fc2d63 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -83,7 +83,7 @@ public static async ValueTask GetEdgeVersion(EngineType engineType } else if (engineType == EngineType.OpenDream) { - var masterBranch = await DummyGitHubService.RealTestClient.Repository.Branch.Get("OpenDreamProject", "OpenDream", "master"); + var masterBranch = await TestingGitHubService.RealTestClient.Repository.Branch.Get("OpenDreamProject", "OpenDream", "master"); byondVersion = new ByondVersion { diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 2ee8cde690a..82613f6a3e6 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -145,7 +145,7 @@ static ushort FreeTcpPort(params ushort[] usedPorts) public static async Task Initialize(TestContext _) { if (TestingUtils.RunningInGitHubActions || String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"))) - await DummyGitHubService.InitializeAndInject(default); + await TestingGitHubService.InitializeAndInject(default); await CachingFileDownloader.InitializeAndInjectForLiveTests(default); diff --git a/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs b/tests/Tgstation.Server.Tests/Live/TestingGitHubService.cs similarity index 93% rename from tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs rename to tests/Tgstation.Server.Tests/Live/TestingGitHubService.cs index ad7470d96f9..99ddbda1ae5 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyGitHubService.cs +++ b/tests/Tgstation.Server.Tests/Live/TestingGitHubService.cs @@ -19,18 +19,18 @@ namespace Tgstation.Server.Tests.Live { - sealed class DummyGitHubService : IAuthenticatedGitHubService + sealed class TestingGitHubService : IAuthenticatedGitHubService { static Dictionary releasesDictionary; static PullRequest testPr; static GitHubCommit testCommit; readonly ICryptographySuite cryptographySuite; - readonly ILogger logger; + readonly ILogger logger; - public static IGitHubClient RealTestClient; + public static readonly IGitHubClient RealTestClient; - public static async Task InitializeAndInject(CancellationToken cancellationToken) + static TestingGitHubService() { var mockOptions = new Mock>(); mockOptions.SetupGet(x => x.Value).Returns(new GeneralConfiguration @@ -40,7 +40,10 @@ public static async Task InitializeAndInject(CancellationToken cancellationToken var gitHubClientFactory = new GitHubClientFactory(new AssemblyInformationProvider(), Mock.Of>(), mockOptions.Object); RealTestClient = gitHubClientFactory.CreateClient(); + } + public static async Task InitializeAndInject(CancellationToken cancellationToken) + { Release targetRelease; do { @@ -73,7 +76,7 @@ public static async Task InitializeAndInject(CancellationToken cancellationToken ServiceCollectionExtensions.UseGitHubServiceFactory(); } - public DummyGitHubService(ICryptographySuite cryptographySuite, ILogger logger) + public TestingGitHubService(ICryptographySuite cryptographySuite, ILogger logger) { this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); From e6615e043b6878a0c2ed8bf0502c377f659b0d28 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 13:24:40 -0400 Subject: [PATCH 047/717] Don't reuse compat ports for OD in Live test --- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 82613f6a3e6..ce996244dde 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -55,6 +55,8 @@ public sealed class TestLiveServer static readonly ushort mainDMPort = FreeTcpPort(mainDDPort); static readonly ushort compatDMPort = FreeTcpPort(mainDDPort, mainDMPort); static readonly ushort compatDDPort = FreeTcpPort(mainDDPort, mainDMPort, compatDMPort); + static readonly ushort odDMPort = FreeTcpPort(mainDDPort, mainDMPort, compatDMPort, compatDDPort); + static readonly ushort odDDPort = FreeTcpPort(mainDDPort, mainDMPort, compatDMPort, compatDDPort, odDMPort); readonly ServerClientFactory clientFactory = new (new ProductHeaderValue(Assembly.GetExecutingAssembly().GetName().Name, Assembly.GetExecutingAssembly().GetName().Version.ToString())); @@ -1144,8 +1146,8 @@ async Task RunInstanceTests() .RunCompatTests( await ByondTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellationToken), adminClient.Instances.CreateClient(compatInstance), - compatDMPort, - compatDDPort, + odDMPort, + odDDPort, server.HighPriorityDreamDaemon, cancellationToken)) : Task.CompletedTask; From 7d2b80f67cd69303f08cfb8e0b504cdc13d597e3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 13:29:10 -0400 Subject: [PATCH 048/717] Check OD interop version --- .../Components/Session/SessionController.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index df2971588dd..b6cfa31e503 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -661,7 +661,8 @@ async ValueTask ProcessBridgeCommand(BridgeParameters parameters return BridgeError("Missing dmApiVersion field!"); DMApiVersion = parameters.Version; - if (DMApiVersion.Major != DMApiConstants.InteropVersion.Major) + if (DMApiVersion.Major != DMApiConstants.InteropVersion.Major + || (ByondVersion.Engine.Value == EngineType.OpenDream && DMApiVersion < new Version(5, 7))) // TODO: When OD figures out how to unite port and topic_port, set an upper version bound on OD for this check { apiValidationStatus = ApiValidationStatus.Incompatible; return BridgeError("Incompatible dmApiVersion!"); From 57b2c8eb4505c449e9f0a9c672dccfe67c4a432c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 13:30:40 -0400 Subject: [PATCH 049/717] Simplify an `ObjectDisposedException` --- .../Components/Session/SessionController.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index b6cfa31e503..b09d1ee7bfa 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -600,11 +600,7 @@ async Task GetLaunchResult( /// /// Throws an if has been called. /// - void CheckDisposed() - { - if (disposed) - throw new ObjectDisposedException(nameof(SessionController)); - } + void CheckDisposed() => ObjectDisposedException.ThrowIf(disposed, this); /// /// Handle a set of bridge . From 2f4aaab0abb863bced0c84b2ee238baaef28c15e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 13:41:27 -0400 Subject: [PATCH 050/717] Additional logging around engine deletion --- .../Components/Engine/EngineManager.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index edd5be0deb0..9ed63b0e268 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -204,13 +204,18 @@ public async ValueTask DeleteVersion(JobProgressReporter progressReporter, Byond throw new JobException(ErrorCode.EngineCannotDeleteActiveVersion); ReferenceCountingContainer container; + logger.LogTrace("Waiting to acquire installedVersions lock..."); lock (installedVersions) + { if (!installedVersions.TryGetValue(version, out container)) { logger.LogTrace("Version {version} already deleted.", version); return; } + logger.LogTrace("Installation container acquired for deletion"); + } + logger.LogInformation("Deleting version {version}...", version); progressReporter.StageName = "Waiting for version to not be in use..."; while (true) @@ -222,6 +227,7 @@ public async ValueTask DeleteVersion(JobProgressReporter progressReporter, Byond using (await SemaphoreSlimContext.Lock(changeDeleteSemaphore, cancellationToken)) activeVersionUpdate = activeVersionChanged.Task; + logger.LogTrace("Waiting for container.OnZeroReferences or switch of active version..."); await Task.WhenAny( containerTask, activeVersionUpdate) @@ -229,6 +235,8 @@ await Task.WhenAny( if (containerTask.IsCompleted) logger.LogTrace("All locks for version {version} are gone", version); + else + logger.LogTrace("activeVersion changed, we'll likely have to wait again. Acquiring semaphore..."); using (await SemaphoreSlimContext.Lock(changeDeleteSemaphore, cancellationToken)) { @@ -237,6 +245,7 @@ await Task.WhenAny( throw new JobException(ErrorCode.EngineCannotDeleteActiveVersion); bool proceed; + logger.LogTrace("Locking installedVersions..."); lock (installedVersions) { proceed = container.OnZeroReferences.IsCompleted; @@ -256,7 +265,10 @@ await Task.WhenAny( } if (proceed) + { + logger.LogTrace("Proceeding with installation deletion..."); installedVersions.Remove(version); + } } } @@ -277,6 +289,8 @@ await ioManager.DeleteFile( logger.LogDebug( "Another lock was acquired before we could remove version {version} from the list. We will have to wait again.", version); + else + logger.LogTrace("Not proceeding for some reason or another"); } } } From a70cbc29a28cbe57ba640cc296c34a41bd23f22a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 14:35:04 -0400 Subject: [PATCH 051/717] Rearrange some logging to make more sense in an async context --- .../Components/Engine/EngineManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index 9ed63b0e268..b09dc5860d5 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -156,11 +156,11 @@ await eventConsumer.HandleEvent( cancellationToken); ActiveVersion = version; + + logger.LogInformation("Active version changed to {version}", version); activeVersionChanged.SetResult(); activeVersionChanged = new TaskCompletionSource(); } - - logger.LogInformation("Active version changed to {version}", version); } /// @@ -236,7 +236,7 @@ await Task.WhenAny( if (containerTask.IsCompleted) logger.LogTrace("All locks for version {version} are gone", version); else - logger.LogTrace("activeVersion changed, we'll likely have to wait again. Acquiring semaphore..."); + logger.LogTrace("activeVersion changed, we may have to wait again. Acquiring semaphore..."); using (await SemaphoreSlimContext.Lock(changeDeleteSemaphore, cancellationToken)) { From 61830a75c8f432ae03b8ff80c660fb18820f0f02 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 14:35:19 -0400 Subject: [PATCH 052/717] Use a thread safe order of operations here just in case --- .../Components/Engine/EngineManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index b09dc5860d5..0ae4dbf9ee5 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -78,7 +78,7 @@ public IReadOnlyList InstalledVersions /// /// that notifes when the changes. /// - TaskCompletionSource activeVersionChanged; + volatile TaskCompletionSource activeVersionChanged; /// /// Validates a given parameter. @@ -158,8 +158,8 @@ await eventConsumer.HandleEvent( ActiveVersion = version; logger.LogInformation("Active version changed to {version}", version); - activeVersionChanged.SetResult(); - activeVersionChanged = new TaskCompletionSource(); + var oldTcs = Interlocked.Exchange(ref activeVersionChanged, new TaskCompletionSource()); + oldTcs.SetResult(); } } From 188932e800cd336711880ad21811e32f18d9b984 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 14:35:34 -0400 Subject: [PATCH 053/717] Compare `ByondVersion` not `Version` --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index a0316338de4..e7de14b3dd3 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -235,7 +235,7 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo var testCustomVersion = new Version(testVersion.Version.Major, testVersion.Version.Minor, 1); var currentByond = await instanceClient.Byond.ActiveVersion(cancellationToken); Assert.IsNotNull(currentByond); - Assert.AreEqual(testVersion.Version.Semver(), currentByond.Version.Version); + Assert.AreEqual(testVersion, currentByond.Version); // Change the active version and check we get delayed while deleting the old one because the watchdog is using it var setActiveResponse = await instanceClient.Byond.SetActiveVersion( From 9c5c5b2ef4c57aa8acfa8ae791876fed6ab01136 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 14:46:04 -0400 Subject: [PATCH 054/717] Woe is me for not using operator overloading --- src/Tgstation.Server.Host/Components/Engine/EngineManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index 0ae4dbf9ee5..ae19ad5d5b8 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -216,7 +216,6 @@ public async ValueTask DeleteVersion(JobProgressReporter progressReporter, Byond logger.LogTrace("Installation container acquired for deletion"); } - logger.LogInformation("Deleting version {version}...", version); progressReporter.StageName = "Waiting for version to not be in use..."; while (true) { @@ -241,7 +240,7 @@ await Task.WhenAny( using (await SemaphoreSlimContext.Lock(changeDeleteSemaphore, cancellationToken)) { // check again because it could have become the active version. - if (version == ActiveVersion) + if (version.Equals(ActiveVersion)) throw new JobException(ErrorCode.EngineCannotDeleteActiveVersion); bool proceed; @@ -274,6 +273,7 @@ await Task.WhenAny( if (proceed) { + logger.LogInformation("Deleting version {version}...", version); progressReporter.StageName = "Deleting installation..."; // delete the version file first, because we will know not to re-discover the installation if it's not present and it will get cleaned on reboot From a1f2a04b9a826f84c2c64d3287a4844a23744084 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 15:27:00 -0400 Subject: [PATCH 055/717] Rearrange OD compat test slightly --- .../Live/TestLiveServer.cs | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index ce996244dde..abb26de2099 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1119,6 +1119,19 @@ async Task FailFast(Task task) async Task RunInstanceTests() { + var odCompatTests = FailFast( + instanceTest + .RunCompatTests( + await ByondTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellationToken), + adminClient.Instances.CreateClient(compatInstance), + odDMPort, + odDDPort, + server.HighPriorityDreamDaemon, + cancellationToken)); + + if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization + await odCompatTests; + // Some earlier linux BYOND versions have a critical bug where replacing the directory in non-basic watchdogs causes the DreamDaemon cwd to change var canRunCompatTests = new PlatformIdentifier().IsWindows; var compatTests = canRunCompatTests @@ -1140,21 +1153,6 @@ async Task RunInstanceTests() if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization await compatTests; - var odCompatTests = canRunCompatTests - ? FailFast( - instanceTest - .RunCompatTests( - await ByondTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellationToken), - adminClient.Instances.CreateClient(compatInstance), - odDMPort, - odDDPort, - server.HighPriorityDreamDaemon, - cancellationToken)) - : Task.CompletedTask; - - if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization - await odCompatTests; - await FailFast( instanceTest .RunTests( From e36fd18378292fd9aded0a9f5e8f279f241cd105 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 16:58:08 -0400 Subject: [PATCH 056/717] Fix issue with non-existent BYOND cfg dir --- .../Components/Engine/ByondInstallerBase.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index e3b18c50c7c..68111c3e99e 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -161,9 +161,11 @@ public override async ValueTask TrustDmbPath(string fullDmbPath, CancellationTok return; } - var trustedFilePath = IOManager.ConcatPath( + var cfgDir = IOManager.ConcatPath( byondDir, - CfgDirectoryName, + CfgDirectoryName); + var trustedFilePath = IOManager.ConcatPath( + cfgDir, TrustedDmbFileName); Logger.LogDebug("Adding .dmb ({dmbPath}) to {trustedFilePath}", fullDmbPath, trustedFilePath); @@ -171,7 +173,8 @@ public override async ValueTask TrustDmbPath(string fullDmbPath, CancellationTok using (await SemaphoreSlimContext.Lock(UserFilesSemaphore, cancellationToken)) { string trustedFileText; - if (await IOManager.FileExists(trustedFilePath, cancellationToken)) + var filePreviouslyExisted = await IOManager.FileExists(trustedFilePath, cancellationToken); + if (filePreviouslyExisted) { var trustedFileBytes = await IOManager.ReadAllBytes(trustedFilePath, cancellationToken); trustedFileText = Encoding.UTF8.GetString(trustedFileBytes); @@ -186,6 +189,10 @@ public override async ValueTask TrustDmbPath(string fullDmbPath, CancellationTok trustedFileText = $"{trustedFileText}{fullDmbPath}{Environment.NewLine}"; var newTrustedFileBytes = Encoding.UTF8.GetBytes(trustedFileText); + + if (!filePreviouslyExisted) + await IOManager.CreateDirectory(cfgDir, cancellationToken); + await IOManager.WriteAllBytes(trustedFilePath, newTrustedFileBytes, cancellationToken); } } From 84c0fcd9030703c0f060879ef8789b6b9001d8db Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 21:54:33 -0400 Subject: [PATCH 057/717] Redo how ByondVersion is implemented to support custom OD builds - `SourceCommittish` -> `SourceSHA`, now MUST be full length. - Fix OpenDreamInstaller.DownloadVersion requiring a JobProgressReporter. - Fix naming of BYOND firewall rules --- .../Models/Internal/ByondVersion.cs | 61 +++++++++++++--- .../Components/Chat/Commands/ByondCommand.cs | 4 +- .../Chat/Providers/DiscordProvider.cs | 4 +- .../Components/Engine/EngineManager.cs | 15 ++-- .../Components/Engine/OpenDreamInstaller.cs | 11 ++- .../Engine/WindowsByondInstaller.cs | 12 ++-- .../Components/Session/SessionController.cs | 4 +- .../Controllers/ByondController.cs | 36 ++++------ .../TestApiClient.cs | 5 +- .../Live/Instance/ByondTest.cs | 37 ++++++---- .../Live/Instance/InstanceTest.cs | 71 ++++++++++++++----- .../Live/Instance/WatchdogTest.cs | 15 ++-- .../Live/TestLiveServer.cs | 7 +- tests/Tgstation.Server.Tests/TestVersions.cs | 18 ++--- tests/Tgstation.Server.Tests/TestingUtils.cs | 33 ++++++++- 15 files changed, 223 insertions(+), 110 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs b/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs index f4617c8394a..297df5df193 100644 --- a/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs +++ b/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs @@ -25,11 +25,17 @@ public class ByondVersion : IEquatable public Version? Version { get; set; } /// - /// The git committish of the engine. On response, this will always be a commit SHA. Currently only valid when is . + /// The git commit SHA of the engine. Currently only valid when is . /// [ResponseOptions] - [StringLength(Limits.MaximumCommitShaLength)] - public string? SourceCommittish { get; set; } + [StringLength(Limits.MaximumCommitShaLength, MinimumLength = Limits.MaximumCommitShaLength)] + public string? SourceSHA { get; set; } + + /// + /// The revision of the custom build. + /// + [ResponseOptions] + public int? CustomIteration { get; set; } /// /// Parses a stringified . @@ -49,7 +55,8 @@ public static bool TryParse(string input, out ByondVersion? byondVersion) return false; EngineType engine; - if (splits.Length > 1) + var hasPrefix = splits.Length > 1; + if (hasPrefix) { if (!Enum.TryParse(splits[0], out engine)) return false; @@ -59,28 +66,46 @@ public static bool TryParse(string input, out ByondVersion? byondVersion) Version? version; string? sha; + int? customRev = null; if (engine == EngineType.Byond) { if (!Version.TryParse(splits.Last(), out version)) return false; + if (version.Build > 0) + { + customRev = version.Build; + version = new Version(version.Major, version.Minor); + } + sha = null; } else { Debug.Assert(engine == EngineType.OpenDream, "This does not support whatever ungodly new engine you've added"); - sha = splits.Last(); + + var shaIndex = hasPrefix ? 1 : 0; + sha = splits[shaIndex]; if (sha.Length != Limits.MaximumCommitShaLength) return false; version = null; + + if (splits.Length - 1 > shaIndex) + { + if (!Int32.TryParse(splits.Last(), out var customRevResult)) + return false; + + customRev = customRevResult; + } } byondVersion = new ByondVersion { Engine = engine, Version = version, - SourceCommittish = sha, + SourceSHA = sha, + CustomIteration = customRev, }; return true; } @@ -103,7 +128,8 @@ public ByondVersion(ByondVersion other) Version = other.Version; Engine = other.Engine; - SourceCommittish = other.SourceCommittish; + SourceSHA = other.SourceSHA; + CustomIteration = other.CustomIteration; } /// @@ -113,7 +139,11 @@ public bool Equals(ByondVersion other) #pragma warning disable CA1062 // Validate arguments of public methods return other!.Version?.Semver() == Version?.Semver() && other.Engine == Engine - && other.SourceCommittish == SourceCommittish; + && (other.SourceSHA == SourceSHA + || (other.SourceSHA != null + && SourceSHA != null + && other.SourceSHA.Equals(SourceSHA, StringComparison.OrdinalIgnoreCase))) + && other.CustomIteration == CustomIteration; #pragma warning restore CA1062 // Validate arguments of public methods } @@ -125,7 +155,20 @@ public override bool Equals(object obj) public override string ToString() { var isByond = Engine == EngineType.Byond; - return $"{(!isByond ? $"{Engine}-" : String.Empty)}{(isByond ? Version : SourceCommittish)}"; // BYOND isn't displayed for backwards compatibility + + // BYOND encodes differently for backwards compatibility + var enginePrefix = !isByond + ? $"{Engine}-" + : String.Empty; + var displayedVersion = isByond + ? (CustomIteration.HasValue + ? new Version(Version!.Major, Version.Minor, CustomIteration.Value) + : Version!).ToString() + : SourceSHA; + var displayedCustomIteration = !isByond && CustomIteration.HasValue + ? $"-{CustomIteration}" + : String.Empty; + return $"{enginePrefix}{displayedVersion}{displayedCustomIteration}"; } /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs index 29a9335be46..6e4f64f3f95 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/ByondCommand.cs @@ -57,11 +57,11 @@ public ValueTask Invoke(string arguments, ChatUser user, Cancell switch (engineManager.ActiveVersion.Engine.Value) { case EngineType.OpenDream: - text = $"OpenDream: {engineManager.ActiveVersion.SourceCommittish}"; + text = $"OpenDream: {engineManager.ActiveVersion.SourceSHA}"; break; case EngineType.Byond: text = $"BYOND {engineManager.ActiveVersion.Version.Major}.{engineManager.ActiveVersion.Version.Minor}"; - if (engineManager.ActiveVersion.Version.Build != -1) + if (engineManager.ActiveVersion.CustomIteration.HasValue) text += " (Custom Build)"; break; diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 013f22fc369..57292f224ac 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -876,11 +876,11 @@ List BuildUpdateEmbedFields( { EngineType.Byond => new EmbedField( "BYOND Version", - $"{byondVersion.Version.Major}.{byondVersion.Version.Minor}{(byondVersion.Version.Build > 0 ? $".{byondVersion.Version.Build}" : String.Empty)}", + $"{byondVersion.Version.Major}.{byondVersion.Version.Minor}{(byondVersion.CustomIteration.HasValue ? $".{byondVersion.CustomIteration.Value}" : String.Empty)}", true), EngineType.OpenDream => new EmbedField( "OpenDream Version", - $"[{byondVersion.SourceCommittish[..7]}]({generalConfiguration.OpenDreamGitUrl}/commit/{revisionInformation.CommitSha})", + $"[{byondVersion.SourceSHA[..7]}]({generalConfiguration.OpenDreamGitUrl}/commit/{byondVersion.SourceSHA})", true), _ => throw new InvalidOperationException($"Invaild EngineType: {byondVersion.Engine.Value}"), }; diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index ae19ad5d5b8..7297d8e07ee 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -66,7 +66,7 @@ public IReadOnlyList InstalledVersions readonly ILogger logger; /// - /// Map of byond s to s that complete when they are installed. + /// Map of byond s to s that complete when they are installed. /// readonly Dictionary> installedVersions; @@ -91,8 +91,8 @@ static void CheckVersionParameter(ByondVersion version) if (!version.Engine.HasValue) throw new InvalidOperationException("version.Engine cannot be null!"); - if (version.Version.Build == 0) - throw new InvalidOperationException("version.Build cannot be 0!"); + if (version.CustomIteration == 0) + throw new InvalidOperationException("version.CustomIteration cannot be 0!"); } /// @@ -138,10 +138,7 @@ public async ValueTask ChangeVersion( cancellationToken); // We reparse the version because it could be changed after a custom install. - version = new ByondVersion(version) - { - Version = installLock.Version.Version, - }; + version = new ByondVersion(installLock.Version); var stringVersion = version.ToString(); await ioManager.WriteAllBytes(ActiveVersionFileName, Encoding.UTF8.GetBytes(stringVersion), cancellationToken); @@ -413,7 +410,7 @@ async ValueTask AssertAndLockVersion( var customInstallationNumber = 1; do { - byondVersion.Version = new Version(byondVersion.Version.Major, byondVersion.Version.Minor, customInstallationNumber++); + byondVersion.CustomIteration = customInstallationNumber++; } while (installedVersions.ContainsKey(byondVersion)); } @@ -455,7 +452,7 @@ async ValueTask AssertAndLockVersion( logger.LogInformation("Installing custom BYOND version as {version}...", byondVersion); else if (neededForLock) { - if (byondEngine && byondVersion.Version.Build > 0) + if (byondEngine && byondVersion.CustomIteration.HasValue) throw new JobException(ErrorCode.EngineNonExistentCustomVersion); logger.LogWarning("The required BYOND version ({version}) is not readily available! We will have to install it.", byondVersion); diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 0436a5eec00..cdecb58fc13 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -112,7 +112,7 @@ public override async ValueTask DownloadVersion(ByondVe // get a lock on a system wide OD repo Logger.LogTrace("Cloning OD repo..."); - var progressSection1 = jobProgressReporter.CreateSection("Updating OpenDream git repository", 0.5f); + var progressSection1 = jobProgressReporter?.CreateSection("Updating OpenDream git repository", 0.5f); var repo = await repositoryManager.CloneRepository( generalConfiguration.OpenDreamGitUrl, @@ -138,11 +138,10 @@ await repo.FetchOrigin( cancellationToken); } - var progressSection2 = jobProgressReporter.CreateSection("Checking out OpenDream version", 0.5f); + var progressSection2 = jobProgressReporter?.CreateSection("Checking out OpenDream version", 0.5f); - var committish = version.SourceCommittish; - if (committish == null) - committish = $"{generalConfiguration.OpenDreamGitTagPrefix}{version.Version.Semver()}"; + var committish = version.SourceSHA + ?? $"{generalConfiguration.OpenDreamGitTagPrefix}{version.Version.Semver()}"; await repo.CheckoutObject( committish, @@ -152,8 +151,6 @@ await repo.CheckoutObject( progressSection2, cancellationToken); - version.SourceCommittish = repo.Head; - return new RepositoryEngineInstallationData(IOManager, repo, InstallationSourceSubDirectory); } catch diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 7795a69b6be..39800f7a7df 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -127,7 +127,7 @@ public override ValueTask Install(ByondVersion version, string path, Cancellatio }; if (!generalConfiguration.SkipAddingByondFirewallException) - tasks.Add(AddDreamDaemonToFirewall(version.Version, path, cancellationToken)); + tasks.Add(AddDreamDaemonToFirewall(version, path, cancellationToken)); return ValueTaskExtensions.WhenAll(tasks); } @@ -148,7 +148,7 @@ public override async ValueTask UpgradeInstallation(ByondVersion version, string return; Logger.LogInformation("BYOND Version {version} needs dd.exe added to firewall", version); - await AddDreamDaemonToFirewall(version.Version, path, cancellationToken); + await AddDreamDaemonToFirewall(version, path, cancellationToken); } /// @@ -224,13 +224,13 @@ async ValueTask InstallDirectX(string path, CancellationToken cancellationToken) /// /// Attempt to add the DreamDaemon executable as an exception to the Windows firewall. /// - /// The BYOND . + /// The BYOND . /// The path to the BYOND installation. /// The for the operation. /// A representing the running operation. - async ValueTask AddDreamDaemonToFirewall(Version byondVersion, string path, CancellationToken cancellationToken) + async ValueTask AddDreamDaemonToFirewall(ByondVersion version, string path, CancellationToken cancellationToken) { - var dreamDaemonName = GetDreamDaemonName(byondVersion, out var usesDDExe); + var dreamDaemonName = GetDreamDaemonName(version.Version, out var usesDDExe); var dreamDaemonPath = IOManager.ResolvePath( IOManager.ConcatPath( @@ -244,7 +244,7 @@ async ValueTask AddDreamDaemonToFirewall(Version byondVersion, string path, Canc // I really wish we could add the instance name here but // 1. It'd make IByondInstaller need to be transient per-instance and WindowsByondInstaller relys on being a singleton for its DX installer call // 2. The instance could be renamed, so it'd have to be an unfriendly ID anyway. - var arguments = $"advfirewall firewall add rule name=\"TGS DreamDaemon {byondVersion}\" program=\"{dreamDaemonPath}\" protocol=tcp dir=in enable=yes action=allow"; + var arguments = $"advfirewall firewall add rule name=\"TGS DreamDaemon {version}\" program=\"{dreamDaemonPath}\" protocol=tcp dir=in enable=yes action=allow"; await using var netshProcess = processExecutor.LaunchProcess( "netsh.exe", IOManager.ResolvePath(), diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index b09d1ee7bfa..2d48efdc410 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -657,8 +657,10 @@ async ValueTask ProcessBridgeCommand(BridgeParameters parameters return BridgeError("Missing dmApiVersion field!"); DMApiVersion = parameters.Version; + + // TODO: When OD figures out how to unite port and topic_port, set an upper version bound on OD for this check if (DMApiVersion.Major != DMApiConstants.InteropVersion.Major - || (ByondVersion.Engine.Value == EngineType.OpenDream && DMApiVersion < new Version(5, 7))) // TODO: When OD figures out how to unite port and topic_port, set an upper version bound on OD for this check + || (ByondVersion.Engine.Value == EngineType.OpenDream && DMApiVersion < new Version(5, 7))) { apiValidationStatus = ApiValidationStatus.Incompatible; return BridgeError("Incompatible dmApiVersion!"); diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index f9cfa3c2136..2022a30a7f7 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -14,7 +14,6 @@ using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Api.Rights; -using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Database; @@ -175,11 +174,10 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode if (versionAlreadyInstalled) { Logger.LogInformation( - "User ID {userId} changing instance ID {instanceId} {engineType} version to {newByondVersion}", + "User ID {userId} changing instance ID {instanceId} engine to {newByondVersion}", AuthenticationContext.User.Id, Instance.Id, - model.Engine, - model.Version); + model); try { @@ -189,26 +187,21 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode { Logger.LogDebug( ex, - "Race condition: {engineType} version {version} uninstalled before we could switch to it. Creating install job instead...", - model.Engine.Value, - model.Version); + "Race condition: Engine {version} uninstalled before we could switch to it. Creating install job instead...", + model); versionAlreadyInstalled = false; } } if (!versionAlreadyInstalled) { - if (model.Version.Build > 0) + if (model.CustomIteration.HasValue) return BadRequest(new ErrorMessageResponse(ErrorCode.EngineNonExistentCustomVersion)); Logger.LogInformation( - "User ID {userId} installing {engineType} version {newByondVersion}{sourceCommittish} on instance ID {instanceId}", + "User ID {userId} installing engine version {newByondVersion} on instance ID {instanceId}", AuthenticationContext.User.Id, - model.Engine.Value, model.Version, - model.SourceCommittish != null - ? $" ({model.SourceCommittish})" - : String.Empty, Instance.Id); // run the install through the job manager @@ -319,7 +312,7 @@ public async ValueTask Delete([FromBody] ByondVersionDeleteReques // run the install through the job manager var job = new Models.Job { - Description = $"Delete installed {model.Engine.Value} version {model.Version}", + Description = $"Delete installed engine version {model}", StartedBy = AuthenticationContext.User, CancelRightsType = RightsType.Byond, CancelRight = (ulong)( @@ -354,21 +347,20 @@ BadRequestObjectResult ValidateByondVersion(ByondVersion version) return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); var isByond = version.Engine.Value == EngineType.Byond; + var validSha = version.SourceSHA?.Length == Limits.MaximumCommitShaLength; if ((isByond && (version.Version == null - || version.Version.Revision != -1 - || version.SourceCommittish != null)) + || validSha)) || (version.Engine.Value == EngineType.OpenDream && - ((version.SourceCommittish == null && version.Version == null) - || (version.Version != null && (version.Version.Revision != -1 || version.Version.Build == -1 || version.SourceCommittish == null))))) + ((version.SourceSHA == null && version.Version == null) + || (version.Version != null && (version.Version.Revision != -1 || validSha))))) return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); if (isByond) - version.Version = NormalizeByondVersion(version.Version); - else if (version.Engine.Value == EngineType.OpenDream && version.Version != null) { - version.SourceCommittish = String.Concat(generalConfiguration.OpenDreamGitTagPrefix, version.Version.Semver()); - version.Version = null; + version.Version = NormalizeByondVersion(version.Version); + if (version.Version.Build != -1) + return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); } return null; diff --git a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs index 74537b9dac5..9747e8b84f7 100644 --- a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs +++ b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs @@ -29,7 +29,7 @@ public async Task TestDeserializingByondModelsWork() Version = new ByondVersion { Engine = EngineType.Byond, - Version = new Version(511, 1385, 0) + Version = new Version(511, 1385) } }; @@ -51,7 +51,8 @@ public async Task TestDeserializingByondModelsWork() var result = await client.Read(Routes.Byond, default); Assert.AreEqual(sample.Version, result.Version); - Assert.AreEqual(0, result.Version.Version.Build); + Assert.AreEqual(0, result.Version.Version.Build); // sucks but we can't do better really + Assert.IsFalse(result.Version.CustomIteration.HasValue); } [TestMethod] diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index 672d2fc2d63..96bd2c09d14 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -88,7 +88,7 @@ public static async ValueTask GetEdgeVersion(EngineType engineType byondVersion = new ByondVersion { Engine = EngineType.OpenDream, - SourceCommittish = masterBranch.Commit.Sha, + SourceSHA = masterBranch.Commit.Sha, }; } else @@ -133,7 +133,8 @@ async Task TestDeletes(CancellationToken cancellationToken) var deleteThisOneBecauseItWasntPartOfTheOriginalTest = await byondClient.DeleteVersion(new ByondVersionDeleteRequest { Engine = testEngine, - Version = new(testVersion.Version.Major, testVersion.Version.Minor, 2) + Version = testVersion.Version, + CustomIteration = 2, }, cancellationToken); await WaitForJob(deleteThisOneBecauseItWasntPartOfTheOriginalTest, 30, false, null, cancellationToken); @@ -150,16 +151,17 @@ async Task TestDeletes(CancellationToken cancellationToken) { Version = testVersion.Version, Engine = testVersion.Engine, - SourceCommittish = testVersion.SourceCommittish, + SourceSHA = testVersion.SourceSHA, }, cancellationToken); var badBecauseActiveResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( new ByondVersionDeleteRequest { - Version = new(testVersion.Version.Major, testVersion.Version.Minor, 1), + Version = testVersion.Version, Engine = testVersion.Engine, - SourceCommittish = testVersion.SourceCommittish, + SourceSHA = testVersion.SourceSHA, + CustomIteration = 1, }, cancellationToken), ErrorCode.EngineCannotDeleteActiveVersion); @@ -180,7 +182,8 @@ async Task TestDeletes(CancellationToken cancellationToken) var newVersions = await byondClient.InstalledVersions(null, cancellationToken); Assert.IsNotNull(newVersions); Assert.AreEqual(1, newVersions.Count); - Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 1), newVersions[0].Version.Version); + Assert.AreEqual(testVersion.Version.Semver(), newVersions[0].Version.Version.Semver()); + Assert.AreEqual(1, newVersions[0].Version.CustomIteration); } async Task TestInstallFakeVersion(CancellationToken cancellationToken) @@ -205,13 +208,14 @@ async Task TestInstallStable(CancellationToken cancellationToken) { Version = testVersion.Version, Engine = testVersion.Engine, - SourceCommittish = testVersion.SourceCommittish, + SourceSHA = testVersion.SourceSHA, }; var test = await byondClient.SetActiveVersion(newModel, null, cancellationToken); Assert.IsNotNull(test.InstallJob); await WaitForJob(test.InstallJob, 180, false, null, cancellationToken); var currentShit = await byondClient.ActiveVersion(cancellationToken); - Assert.AreEqual(newModel.Version.Semver(), currentShit.Version.Version); + Assert.AreEqual(newModel, currentShit.Version); + Assert.IsFalse(currentShit.Version.CustomIteration.HasValue); var dreamMaker = "DreamMaker"; if (new PlatformIdentifier().IsWindows) @@ -262,14 +266,14 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) using var windowsByondInstaller = byondInstaller as WindowsByondInstaller; // get the bytes for stable - using var stableBytesMs = TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(testVersion, null, cancellationToken)); + await using var stableBytesMs = await TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(testVersion, null, cancellationToken), cancellationToken); var test = await byondClient.SetActiveVersion( new ByondVersionRequest { Engine = testVersion.Engine, Version = testVersion.Version, - SourceCommittish = testVersion.SourceCommittish, + SourceSHA = testVersion.SourceSHA, UploadCustomZip = true }, stableBytesMs, @@ -284,7 +288,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) new ByondVersionRequest { Version = testVersion.Version, - SourceCommittish = testVersion.SourceCommittish, + SourceSHA = testVersion.SourceSHA, Engine = testVersion.Engine, UploadCustomZip = true }, @@ -295,26 +299,29 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) await WaitForJob(test2.InstallJob, 30, false, null, cancellationToken); var newSettings = await byondClient.ActiveVersion(cancellationToken); - Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 2), newSettings.Version.Version); + Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 0), newSettings.Version.Version); + Assert.AreEqual(2, newSettings.Version.CustomIteration); // test a few switches var installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest { Version = testVersion.Version, - SourceCommittish = testVersion.SourceCommittish, + SourceSHA = testVersion.SourceSHA, Engine = testVersion.Engine, }, null, cancellationToken); Assert.IsNull(installResponse.InstallJob); await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(new ByondVersionRequest { - Version = new Version(testVersion.Version.Major, testVersion.Version.Minor, 3), + Version = testVersion.Version, Engine = testEngine, + CustomIteration = 3, }, null, cancellationToken), ErrorCode.EngineNonExistentCustomVersion); installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest { - Version = new Version(testVersion.Version.Major, testVersion.Version.Minor, 1), + Version = new Version(testVersion.Version.Major, testVersion.Version.Minor), Engine = testEngine, + CustomIteration = 1, }, null, cancellationToken); Assert.IsNull(installResponse.InstallJob); } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index ae100a465ac..67f2d6ee9bb 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -18,6 +19,8 @@ using Tgstation.Server.Client.Components; using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Components.Engine; +using Tgstation.Server.Host.Components.Events; +using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; @@ -71,11 +74,11 @@ public async Task RunCompatTests( bool highPrioDD, CancellationToken cancellationToken) { - if (compatVersion.Engine != EngineType.Byond) -#if !DEBUG - Assert.Fail("Compat test for OD not release ready!"); -#else + if (compatVersion.Engine.Value == EngineType.OpenDream) +#if DEBUG return; +#else + Assert.Fail("OD Compat test not ready!"); #endif System.Console.WriteLine($"COMPAT TEST START: {compatVersion}"); const string Origin = "https://github.com/Cyberboss/common_core"; @@ -132,31 +135,56 @@ public async Task RunCompatTests( var jrt = new JobsRequiredTest(instanceClient.Jobs); - IEngineInstaller byondInstaller = new PlatformIdentifier().IsWindows - ? new WindowsByondInstaller( + + var odRepoDir = Path.GetFullPath(Path.Combine(instanceClient.Metadata.Path, "..", "OpenDreamRepo")); + var tmpIOManager = new ResolvingIOManager(new DefaultIOManager(), odRepoDir); + + var mockOptions = new Mock>(); + mockOptions.SetupGet(x => x.Value).Returns(new GeneralConfiguration()); + IEngineInstaller byondInstaller = + compatVersion.Engine == EngineType.OpenDream + ? new OpenDreamInstaller( + new DefaultIOManager(), + Mock.Of>(), + new PlatformIdentifier(), Mock.Of(), - Mock.Of(), - fileDownloader, - Options.Create(new GeneralConfiguration()), - Mock.Of>()) - : new PosixByondInstaller( - Mock.Of(), - Mock.Of(), - fileDownloader, - Mock.Of>()); + new RepositoryManager( + new LibGit2RepositoryFactory( + Mock.Of>()), + new LibGit2Commands(), + tmpIOManager, + new NoopEventConsumer(), + Mock.Of(), + Mock.Of(), + Mock.Of>(), + Mock.Of>(), + new GeneralConfiguration()), + mockOptions.Object) + : new PlatformIdentifier().IsWindows + ? new WindowsByondInstaller( + Mock.Of(), + Mock.Of(), + fileDownloader, + Options.Create(new GeneralConfiguration()), + Mock.Of>()) + : new PosixByondInstaller( + Mock.Of(), + Mock.Of(), + fileDownloader, + Mock.Of>()); using var windowsByondInstaller = byondInstaller as WindowsByondInstaller; // get the bytes for stable ByondInstallResponse installJob2; - using (var stableBytesMs = TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(compatVersion, null, cancellationToken))) + await using (var stableBytesMs = await TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(compatVersion, null, cancellationToken), cancellationToken)) { installJob2 = await instanceClient.Byond.SetActiveVersion(new ByondVersionRequest { UploadCustomZip = true, Version = compatVersion.Version, Engine = compatVersion.Engine, - SourceCommittish = compatVersion.SourceCommittish + SourceSHA = compatVersion.SourceSHA }, stableBytesMs, cancellationToken); } @@ -173,6 +201,15 @@ await Task.WhenAll( dmUpdateRequest.AsTask(), cloneRequest); + if (compatVersion.Engine.Value == EngineType.OpenDream) + { + Assert.IsNotNull(compatVersion.SourceSHA); + Assert.AreNotEqual(Limits.MaximumCommitShaLength, compatVersion.SourceSHA.Length); + var activeVersion = await instanceClient.Byond.ActiveVersion(cancellationToken); + Assert.AreEqual(Limits.MaximumCommitShaLength, activeVersion.Version.SourceSHA.Length); + Assert.AreEqual(compatVersion, activeVersion.Version); + } + var configSetupTask = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata).SetupDMApiTests(cancellationToken); if (TestingUtils.RunningInGitHubActions diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index e7de14b3dd3..c0f3f52ed8d 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -94,7 +94,7 @@ async Task CheckByondVersions() Assert.AreEqual(1, list.Count); var byondVersion = list[0]; - Assert.AreEqual(1, byondVersion.Version.Version.Build); + Assert.AreEqual(1, byondVersion.Version.CustomIteration); Assert.AreEqual(testVersion.Version.Major, byondVersion.Version.Version.Major); Assert.AreEqual(testVersion.Version.Minor, byondVersion.Version.Version.Minor); Assert.AreEqual(testVersion.Engine, byondVersion.Version.Engine); @@ -232,7 +232,8 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationToken cancellationToken) { - var testCustomVersion = new Version(testVersion.Version.Major, testVersion.Version.Minor, 1); + var testCustomVersion = testVersion.Version; + var testCustomRevision = 1; var currentByond = await instanceClient.Byond.ActiveVersion(cancellationToken); Assert.IsNotNull(currentByond); Assert.AreEqual(testVersion, currentByond.Version); @@ -243,6 +244,7 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo { Version = testCustomVersion, Engine = testVersion.Engine, + CustomIteration = testCustomRevision, }, null, cancellationToken); @@ -254,7 +256,7 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo new ByondVersionDeleteRequest { Version = testVersion.Version, - SourceCommittish = testVersion.SourceCommittish, + SourceSHA = testVersion.SourceSHA, Engine = testVersion.Engine, }, cancellationToken); @@ -272,7 +274,7 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo { Version = testVersion.Version, Engine = testVersion.Engine, - SourceCommittish = testVersion.SourceCommittish + SourceSHA = testVersion.SourceSHA }, null, cancellationToken); @@ -289,6 +291,7 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo { Version = testCustomVersion, Engine = testVersion.Engine, + CustomIteration = testCustomRevision, }, null, cancellationToken); @@ -301,7 +304,7 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo { Version = testVersion.Version, Engine = testVersion.Engine, - SourceCommittish = testVersion.SourceCommittish, + SourceSHA = testVersion.SourceSHA, }, cancellationToken); @@ -980,7 +983,7 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken { Version = versionToInstall.Version, Engine = versionToInstall.Engine, - SourceCommittish = versionToInstall.SourceCommittish, + SourceSHA = versionToInstall.SourceSHA, }, null, cancellationToken); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index abb26de2099..092e55888f9 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1103,8 +1103,10 @@ async Task FailFast(Task task) var usersTest = FailFast(new UsersTest(adminClient).Run(cancellationToken)); var instanceManagerTest = new InstanceManagerTest(adminClient, server.Directory); var compatInstanceTask = instanceManagerTest.CreateTestInstance("CompatTestsInstance", cancellationToken); + var odInstanceTask = instanceManagerTest.CreateTestInstance("OdTestsInstance", cancellationToken); instance = await instanceManagerTest.CreateTestInstance("LiveTestsInstance", cancellationToken); var compatInstance = await compatInstanceTask; + var odInstance = await odInstanceTask; var instancesTest = FailFast(instanceManagerTest.RunPreTest(cancellationToken)); Assert.IsTrue(Directory.Exists(instance.Path)); var instanceClient = adminClient.Instances.CreateClient(instance); @@ -1123,7 +1125,7 @@ async Task RunInstanceTests() instanceTest .RunCompatTests( await ByondTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellationToken), - adminClient.Instances.CreateClient(compatInstance), + adminClient.Instances.CreateClient(odInstance), odDMPort, odDDPort, server.HighPriorityDreamDaemon, @@ -1132,6 +1134,9 @@ await ByondTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellatio if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization await odCompatTests; + await odCompatTests; + Assert.Fail("!!!SUCCESS!!!"); + // Some earlier linux BYOND versions have a critical bug where replacing the directory in non-basic watchdogs causes the DreamDaemon cwd to change var canRunCompatTests = new PlatformIdentifier().IsWindows; var compatTests = canRunCompatTests diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index eac841d7bc7..d7d10c53381 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -127,7 +127,7 @@ await CachingFileDownloader.InitializeByondVersion( const string ArchiveEntryPath = "byond/bin/dd.exe"; var hasEntry = ArchiveHasFileEntry( - TestingUtils.ExtractMemoryStreamFromInstallationData( + await TestingUtils.ExtractMemoryStreamFromInstallationData( await byondInstaller.DownloadVersion( new ByondVersion { @@ -135,7 +135,8 @@ await byondInstaller.DownloadVersion( Version = WindowsByondInstaller.DDExeVersion }, null, - default)), + default), + CancellationToken.None), ArchiveEntryPath); Assert.IsTrue(hasEntry); @@ -220,7 +221,7 @@ await TestMapThreadsVersion( Engine = EngineType.Byond, Version = MapThreadsVersion(), }, - TestingUtils.ExtractMemoryStreamFromInstallationData( + await TestingUtils.ExtractMemoryStreamFromInstallationData( await byondInstaller.DownloadVersion( new ByondVersion { @@ -228,7 +229,8 @@ await byondInstaller.DownloadVersion( Version = MapThreadsVersion() }, null, - default)), + default), + CancellationToken.None), byondInstaller, ioManager, processExecutor, @@ -414,19 +416,19 @@ static async Task> GetByondVersionPriorTo(Byon }; try { - return Tuple.Create(TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion( + return Tuple.Create(await TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion( byondVersion, null, - CancellationToken.None)), byondVersion); + CancellationToken.None), CancellationToken.None), byondVersion); } catch (HttpRequestException) { var minusOneMajor = new Version(minusOneMinor.Major - 1, minusOneMinor.Minor); byondVersion.Version = minusOneMajor; - return Tuple.Create(TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion( + return Tuple.Create(await TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion( byondVersion, null, - CancellationToken.None)), byondVersion); + CancellationToken.None), CancellationToken.None), byondVersion); } } diff --git a/tests/Tgstation.Server.Tests/TestingUtils.cs b/tests/Tgstation.Server.Tests/TestingUtils.cs index 7b4a62fc248..5ec99ab4853 100644 --- a/tests/Tgstation.Server.Tests/TestingUtils.cs +++ b/tests/Tgstation.Server.Tests/TestingUtils.cs @@ -1,12 +1,16 @@ using System; using System.IO; +using System.IO.Compression; using System.Reflection; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Tgstation.Server.Host.Components.Engine; +using Tgstation.Server.Host.IO; namespace Tgstation.Server.Tests { @@ -29,10 +33,33 @@ public static ILoggerFactory CreateLoggerFactoryForLogger(ILogger logger, out Mo return mockLoggerFactory.Object; } - public static MemoryStream ExtractMemoryStreamFromInstallationData(IEngineInstallationData engineInstallationData) + public static async ValueTask ExtractMemoryStreamFromInstallationData(IEngineInstallationData engineInstallationData, CancellationToken cancellationToken) { - var zipStreamData = (ZipStreamEngineInstallationData)engineInstallationData; - return (MemoryStream)zipStreamData.GetType().GetField("zipStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData); + if (engineInstallationData is ZipStreamEngineInstallationData zipStreamData) + return (MemoryStream)zipStreamData.GetType().GetField("zipStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData); + + await using var repoData = (RepositoryEngineInstallationData)engineInstallationData; + var tempFolder = Path.GetTempFileName(); + File.Delete(tempFolder); + try + { + await repoData.ExtractToPath(tempFolder, cancellationToken); + var resultStream = new MemoryStream(); + try + { + ZipFile.CreateFromDirectory(tempFolder, resultStream, CompressionLevel.NoCompression, false); + return resultStream; + } + catch + { + await resultStream.DisposeAsync(); + throw; + } + } + finally + { + await new DefaultIOManager().DeleteDirectory(tempFolder, cancellationToken); + } } } } From e05e79b5175370ca54e8c2890e9e4fb9e775c56e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 21:54:56 -0400 Subject: [PATCH 058/717] Setup Windows Firewall handling for OpenDream --- src/Tgstation.Server.Api/Models/ErrorCode.cs | 4 +- .../Components/Engine/OpenDreamInstaller.cs | 54 +++++++---- .../Engine/WindowsByondInstaller.cs | 47 ++++----- .../Engine/WindowsOpenDreamInstaller.cs | 97 +++++++++++++++++++ src/Tgstation.Server.Host/Core/Application.cs | 3 +- .../System/WindowsFirewallHelper.cs | 52 ++++++++++ .../Live/TestLiveServer.cs | 2 +- 7 files changed, 207 insertions(+), 52 deletions(-) create mode 100644 src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs create mode 100644 src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs diff --git a/src/Tgstation.Server.Api/Models/ErrorCode.cs b/src/Tgstation.Server.Api/Models/ErrorCode.cs index 9261772de8f..00800b4aa7a 100644 --- a/src/Tgstation.Server.Api/Models/ErrorCode.cs +++ b/src/Tgstation.Server.Api/Models/ErrorCode.cs @@ -566,8 +566,8 @@ public enum ErrorCode : uint /// /// Attempt to add DreamDaemon to the list of firewall exempt processes failed. /// - [Description("Failed to allow DreamDaemon through the Windows firewall!")] - ByondDreamDaemonFirewallFail, + [Description("Failed to allow game server through the Windows firewall!")] + EngineFirewallFail, /// /// Attempted to create an instance but no free ports could be found. diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index cdecb58fc13..a99da31ad21 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -21,7 +21,7 @@ namespace Tgstation.Server.Host.Components.Engine /// /// Implementation of for . /// - sealed class OpenDreamInstaller : EngineInstallerBase + class OpenDreamInstaller : EngineInstallerBase { /// /// The name of the subdirectory used to store the server and compiler binaries. @@ -37,14 +37,14 @@ sealed class OpenDreamInstaller : EngineInstallerBase protected override EngineType TargetEngineType => EngineType.OpenDream; /// - /// The for the . + /// The for the . /// - readonly IPlatformIdentifier platformIdentifier; + protected IProcessExecutor ProcessExecutor { get; } /// - /// The for the . + /// The for the . /// - readonly IProcessExecutor processExecutor; + readonly IPlatformIdentifier platformIdentifier; /// /// The for the OpenDream repository. @@ -62,7 +62,7 @@ sealed class OpenDreamInstaller : EngineInstallerBase /// The for the . /// The for the . /// The value of . - /// The value of . + /// The value of . /// The value of . /// The containing value of . public OpenDreamInstaller( @@ -75,7 +75,7 @@ public OpenDreamInstaller( : base(ioManager, logger) { this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); - this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); + ProcessExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); this.repositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } @@ -87,19 +87,10 @@ public OpenDreamInstaller( public override IEngineInstallation CreateInstallation(ByondVersion version, string path, Task installationTask) { CheckVersionValidity(version); - var binPathForVersion = IOManager.ConcatPath(path, InstallationBinDirectory); - - var exeExtension = platformIdentifier.IsWindows - ? ".exe" - : String.Empty; - + GetExecutablePaths(path, out var serverExePath, out var compilerExePath); return new OpenDreamInstallation( - IOManager.ConcatPath( - binPathForVersion, - $"OpenDreamServer{exeExtension}"), - IOManager.ConcatPath( - binPathForVersion, - $"DMCompiler{exeExtension}"), + serverExePath, + compilerExePath, installationTask, version); } @@ -215,7 +206,7 @@ public override async ValueTask Install(ByondVersion version, string installPath var dotnetPath = dotnetPaths[selectedPathIndex]; - await using (var buildProcess = processExecutor.LaunchProcess( + await using (var buildProcess = ProcessExecutor.LaunchProcess( dotnetPath, sourcePath, "build -c Release /p:TgsEngineBuild=true", @@ -255,5 +246,28 @@ public override ValueTask TrustDmbPath(string fullDmbPath, CancellationToken can ArgumentNullException.ThrowIfNull(fullDmbPath); return ValueTask.CompletedTask; } + + /// + /// Gets the paths to the server and client executables. + /// + /// The path to the OpenDream installation. + /// The path to the OpenDreamServer executable. + /// The path to the DMCompiler executable. + protected void GetExecutablePaths(string installationPath, out string serverExePath, out string compilerExePath) + { + var binPathForVersion = IOManager.ConcatPath(installationPath, InstallationBinDirectory); + + var exeExtension = platformIdentifier.IsWindows + ? ".exe" + : String.Empty; + + serverExePath = IOManager.ConcatPath( + binPathForVersion, + $"OpenDreamServer{exeExtension}"); + + compilerExePath = IOManager.ConcatPath( + binPathForVersion, + $"DMCompiler{exeExtension}"); + } } } diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 39800f7a7df..60077b006b1 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -238,43 +238,34 @@ async ValueTask AddDreamDaemonToFirewall(ByondVersion version, string path, Canc BinPath, dreamDaemonName)); - Logger.LogInformation("Adding Windows Firewall exception for {path}...", dreamDaemonPath); + int exitCode; try { // I really wish we could add the instance name here but // 1. It'd make IByondInstaller need to be transient per-instance and WindowsByondInstaller relys on being a singleton for its DX installer call // 2. The instance could be renamed, so it'd have to be an unfriendly ID anyway. - var arguments = $"advfirewall firewall add rule name=\"TGS DreamDaemon {version}\" program=\"{dreamDaemonPath}\" protocol=tcp dir=in enable=yes action=allow"; - await using var netshProcess = processExecutor.LaunchProcess( - "netsh.exe", - IOManager.ResolvePath(), - arguments, - readStandardHandles: true, - noShellExecute: true); - - int exitCode; - using (cancellationToken.Register(() => netshProcess.Terminate())) - exitCode = (await netshProcess.Lifetime).Value; - cancellationToken.ThrowIfCancellationRequested(); - - Logger.LogDebug( - "netsh.exe output:{newLine}{output}", - Environment.NewLine, - await netshProcess.GetCombinedOutput(cancellationToken)); - - if (exitCode != 0) - throw new JobException(ErrorCode.ByondDreamDaemonFirewallFail, new JobException($"Invalid exit code: {exitCode}")); - - if (usesDDExe) - await IOManager.WriteAllBytes( - IOManager.ConcatPath(path, TgsFirewalledDDFile), - Array.Empty(), - cancellationToken); + var ruleName = $"TGS DreamDaemon {version}"; + + exitCode = await WindowsFirewallHelper.AddFirewallException( + processExecutor, + Logger, + ruleName, + dreamDaemonPath, + cancellationToken); } catch (Exception ex) { - throw new JobException(ErrorCode.ByondDreamDaemonFirewallFail, ex); + throw new JobException(ErrorCode.EngineFirewallFail, ex); } + + if (exitCode != 0) + throw new JobException(ErrorCode.EngineFirewallFail, new JobException($"Invalid exit code: {exitCode}")); + + if (usesDDExe) + await IOManager.WriteAllBytes( + IOManager.ConcatPath(path, TgsFirewalledDDFile), + [], + cancellationToken); } } } diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs new file mode 100644 index 00000000000..de37cc8b5f7 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -0,0 +1,97 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Common.Extensions; +using Tgstation.Server.Host.Components.Repository; +using Tgstation.Server.Host.Configuration; +using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.Jobs; +using Tgstation.Server.Host.System; + +namespace Tgstation.Server.Host.Components.Engine +{ + /// + /// Implementation of for Windows systems. + /// + sealed class WindowsOpenDreamInstaller : OpenDreamInstaller + { + /// + /// Initializes a new instance of the class. + /// + /// The for the . + /// The for the . + /// The for the . + /// The for the . + /// The for the . + /// The of for the . + public WindowsOpenDreamInstaller( + IIOManager ioManager, + ILogger logger, + IPlatformIdentifier platformIdentifier, + IProcessExecutor processExecutor, + IRepositoryManager repositoryManager, + IOptions generalConfigurationOptions) + : base( + ioManager, + logger, + platformIdentifier, + processExecutor, + repositoryManager, + generalConfigurationOptions) + { + } + + /// + public override ValueTask Install(ByondVersion version, string installPath, CancellationToken cancellationToken) + => ValueTaskExtensions.WhenAll( + base.Install( + version, + installPath, + cancellationToken), + AddServerFirewallException( + version, + installPath, + cancellationToken)); + + /// + /// Attempt to add the DreamDaemon executable as an exception to the Windows firewall. + /// + /// The BYOND . + /// The path to the BYOND installation. + /// The for the operation. + /// A representing the running operation. + async ValueTask AddServerFirewallException(ByondVersion version, string path, CancellationToken cancellationToken) + { + GetExecutablePaths(path, out var serverExePath, out _); + + int exitCode; + try + { + // I really wish we could add the instance name here but + // 1. It'd make IByondInstaller need to be transient per-instance and WindowsByondInstaller relys on being a singleton for its DX installer call + // 2. The instance could be renamed, so it'd have to be an unfriendly ID anyway. + var ruleName = $"TGS DreamDaemon {version}"; + + exitCode = await WindowsFirewallHelper.AddFirewallException( + ProcessExecutor, + Logger, + ruleName, + serverExePath, + cancellationToken); + } + catch (Exception ex) + { + throw new JobException(ErrorCode.EngineFirewallFail, ex); + } + + if (exitCode != 0) + throw new JobException(ErrorCode.EngineFirewallFail, new JobException($"Invalid exit code: {exitCode}")); + } + } +} diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 4931fc9302b..75421c24ac4 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -335,6 +335,7 @@ void AddTypedContext() services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -348,6 +349,7 @@ void AddTypedContext() services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -373,7 +375,6 @@ void AddTypedContext() openDreamRepositoryDirectory), new NoopEventConsumer())); - services.AddSingleton(); services.AddSingleton>( serviceProvider => new Dictionary { diff --git a/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs b/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs new file mode 100644 index 00000000000..74964a5569f --- /dev/null +++ b/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs @@ -0,0 +1,52 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.Extensions.Logging; + +namespace Tgstation.Server.Host.System +{ + /// + /// Helper for interacting with the Windows Firewall. + /// + static class WindowsFirewallHelper + { + /// + /// Add an executable exception to the Windows firewall. + /// + /// The to use. + /// The to write to. + /// The name of the rule in Windows Firewall. + /// The path to the .exe to add a firewall exception for. + /// The for the operation. + /// A resulting in the exit code of the call to netsh.exe. + public static async ValueTask AddFirewallException( + IProcessExecutor processExecutor, + ILogger logger, + string exceptionName, + string exePath, + CancellationToken cancellationToken) + { + logger.LogInformation("Adding Windows Firewall exception for {path}...", exePath); + var arguments = $"advfirewall firewall add rule name=\"{exceptionName}\" program=\"{exePath}\" protocol=tcp dir=in enable=yes action=allow"; + await using var netshProcess = processExecutor.LaunchProcess( + "netsh.exe", + Environment.CurrentDirectory, + arguments, + readStandardHandles: true, + noShellExecute: true); + + int exitCode; + using (cancellationToken.Register(() => netshProcess.Terminate())) + exitCode = (await netshProcess.Lifetime).Value; + cancellationToken.ThrowIfCancellationRequested(); + + logger.LogDebug( + "netsh.exe output:{newLine}{output}", + Environment.NewLine, + await netshProcess.GetCombinedOutput(cancellationToken)); + + return exitCode; + } + } +} diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 092e55888f9..9f4a7fc72a2 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1135,7 +1135,7 @@ await ByondTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellatio await odCompatTests; await odCompatTests; - Assert.Fail("!!!SUCCESS!!!"); + // Assert.Fail("!!!SUCCESS!!!"); // Some earlier linux BYOND versions have a critical bug where replacing the directory in non-basic watchdogs causes the DreamDaemon cwd to change var canRunCompatTests = new PlatformIdentifier().IsWindows; From 9995f449b336eb76f72ea26bdc332cd460cc3015 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 22:04:31 -0400 Subject: [PATCH 059/717] Log `ByondVersion` not `Version` --- src/Tgstation.Server.Host/Controllers/ByondController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index 2022a30a7f7..45447a2fbf4 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -201,7 +201,7 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode Logger.LogInformation( "User ID {userId} installing engine version {newByondVersion} on instance ID {instanceId}", AuthenticationContext.User.Id, - model.Version, + model, Instance.Id); // run the install through the job manager From 947ec44e058aa991a1b731d8aeff3dc972b10ec8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 22:05:32 -0400 Subject: [PATCH 060/717] Fix stream seeking in test --- tests/Tgstation.Server.Tests/TestingUtils.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Tgstation.Server.Tests/TestingUtils.cs b/tests/Tgstation.Server.Tests/TestingUtils.cs index 5ec99ab4853..51f1bf3f130 100644 --- a/tests/Tgstation.Server.Tests/TestingUtils.cs +++ b/tests/Tgstation.Server.Tests/TestingUtils.cs @@ -48,6 +48,7 @@ public static async ValueTask ExtractMemoryStreamFromInstallationD try { ZipFile.CreateFromDirectory(tempFolder, resultStream, CompressionLevel.NoCompression, false); + resultStream.Seek(0, SeekOrigin.Begin); return resultStream; } catch From 7671eeeb25eec0348bf66a55f364fee1ea68ac1d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 22:24:22 -0400 Subject: [PATCH 061/717] Simplify OD install paths --- src/Tgstation.Server.Host/Components/Engine/EngineManager.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index 7297d8e07ee..0b7367076d9 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -501,10 +501,7 @@ async ValueTask AssertAndLockVersion( /// A representing the running operation. async ValueTask InstallVersionFiles(JobProgressReporter progressReporter, ByondVersion version, Stream customVersionStream, CancellationToken cancellationToken) { - var installFullPath = ioManager.ResolvePath( - version.Engine == EngineType.Byond - ? version.ToString() - : Guid.NewGuid().ToString()); // too much BS with OD i swear, we can't use the provided committish because it may expand later + var installFullPath = ioManager.ResolvePath(version.ToString()); async ValueTask DirectoryCleanup() { await ioManager.DeleteDirectory(installFullPath, cancellationToken); From 0544c0241c7286fc5826521116cc1b5693b42e04 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 22:24:37 -0400 Subject: [PATCH 062/717] Log OD build output --- .../Components/Engine/OpenDreamInstaller.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index a99da31ad21..dc0bb371ec2 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -215,6 +215,9 @@ public override async ValueTask Install(ByondVersion version, string installPath true)) { var buildExitCode = await buildProcess.Lifetime; + + Logger.LogDebug("Build output:{newLine}{output}", Environment.NewLine, await buildProcess.GetCombinedOutput(cancellationToken)); + if (buildExitCode != 0) throw new JobException("OpenDream build failed!"); } From 1f2e4494a2f3165489118743afa03ee85abfdc97 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 22:47:14 -0400 Subject: [PATCH 063/717] Fix OD build paths being too long on Windows --- .../Components/Engine/OpenDreamInstaller.cs | 43 +++++++++++++------ .../Engine/WindowsOpenDreamInstaller.cs | 25 ++++++++++- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index dc0bb371ec2..1aa0bec4ec0 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -206,21 +206,25 @@ public override async ValueTask Install(ByondVersion version, string installPath var dotnetPath = dotnetPaths[selectedPathIndex]; - await using (var buildProcess = ProcessExecutor.LaunchProcess( - dotnetPath, + int? buildExitCode = null; + await HandleExtremelyLongPathOperation( + async shortenedPath => + { + await using var buildProcess = ProcessExecutor.LaunchProcess( + dotnetPath, + shortenedPath, + "build -c Release /p:TgsEngineBuild=true", + null, + true, + true); + buildExitCode = await buildProcess.Lifetime; + Logger.LogDebug("Build output:{newLine}{output}", Environment.NewLine, await buildProcess.GetCombinedOutput(cancellationToken)); + }, sourcePath, - "build -c Release /p:TgsEngineBuild=true", - null, - true, - true)) - { - var buildExitCode = await buildProcess.Lifetime; - - Logger.LogDebug("Build output:{newLine}{output}", Environment.NewLine, await buildProcess.GetCombinedOutput(cancellationToken)); + cancellationToken); - if (buildExitCode != 0) - throw new JobException("OpenDream build failed!"); - } + if (buildExitCode != 0) + throw new JobException("OpenDream build failed!"); await IOManager.MoveDirectory( IOManager.ConcatPath( @@ -250,6 +254,19 @@ public override ValueTask TrustDmbPath(string fullDmbPath, CancellationToken can return ValueTask.CompletedTask; } + /// + /// Perform an operation on a very long path. + /// + /// A taking a shortened path and resulting in a representing the running operation. + /// The original path to the directory. + /// The for the operation. + /// A representing the running operation. + protected virtual ValueTask HandleExtremelyLongPathOperation( + Func shortenedPathOperation, + string originalPath, + CancellationToken cancellationToken) + => shortenedPathOperation(originalPath); // based god linux has no such weakness + /// /// Gets the paths to the server and client executables. /// diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index de37cc8b5f7..20162e432e5 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -21,6 +21,11 @@ namespace Tgstation.Server.Host.Components.Engine /// sealed class WindowsOpenDreamInstaller : OpenDreamInstaller { + /// + /// The for the . + /// + readonly ISymlinkFactory symlinkFactory; + /// /// Initializes a new instance of the class. /// @@ -30,13 +35,15 @@ sealed class WindowsOpenDreamInstaller : OpenDreamInstaller /// The for the . /// The for the . /// The of for the . + /// The value of . public WindowsOpenDreamInstaller( IIOManager ioManager, ILogger logger, IPlatformIdentifier platformIdentifier, IProcessExecutor processExecutor, IRepositoryManager repositoryManager, - IOptions generalConfigurationOptions) + IOptions generalConfigurationOptions, + ISymlinkFactory symlinkFactory) : base( ioManager, logger, @@ -45,6 +52,7 @@ public WindowsOpenDreamInstaller( repositoryManager, generalConfigurationOptions) { + this.symlinkFactory = symlinkFactory ?? throw new ArgumentNullException(nameof(symlinkFactory)); } /// @@ -59,6 +67,21 @@ public override ValueTask Install(ByondVersion version, string installPath, Canc installPath, cancellationToken)); + /// + protected override async ValueTask HandleExtremelyLongPathOperation(Func shortenedPathOperation, string originalPath, CancellationToken cancellationToken) + { + var shortPath = $"C:/{Guid.NewGuid()}"; + await symlinkFactory.CreateSymbolicLink(originalPath, shortPath, cancellationToken); + try + { + await shortenedPathOperation(shortPath); + } + finally + { + await IOManager.DeleteDirectory(shortPath, CancellationToken.None); // DCT: Should always run. + } + } + /// /// Attempt to add the DreamDaemon executable as an exception to the Windows firewall. /// From cb7bddb481c1eeff63d46556d843fc09e24549d9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 22:47:29 -0400 Subject: [PATCH 064/717] Fix test OD repo extraction --- tests/Tgstation.Server.Tests/TestVersions.cs | 2 +- tests/Tgstation.Server.Tests/TestingUtils.cs | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index d7d10c53381..1e5fc87139c 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -406,7 +406,7 @@ static string GetMigrationTimestampString(Type type) => type Assert.AreEqual(latestMigrationSL, DatabaseContext.SLLatestMigration); } - static async Task> GetByondVersionPriorTo(ByondInstallerBase byondInstaller, Version version) + static async Task> GetByondVersionPriorTo(ByondInstallerBase byondInstaller, Version version) { var minusOneMinor = new Version(version.Major, version.Minor - 1); var byondVersion = new ByondVersion diff --git a/tests/Tgstation.Server.Tests/TestingUtils.cs b/tests/Tgstation.Server.Tests/TestingUtils.cs index 51f1bf3f130..b40e940e398 100644 --- a/tests/Tgstation.Server.Tests/TestingUtils.cs +++ b/tests/Tgstation.Server.Tests/TestingUtils.cs @@ -33,7 +33,7 @@ public static ILoggerFactory CreateLoggerFactoryForLogger(ILogger logger, out Mo return mockLoggerFactory.Object; } - public static async ValueTask ExtractMemoryStreamFromInstallationData(IEngineInstallationData engineInstallationData, CancellationToken cancellationToken) + public static async ValueTask ExtractMemoryStreamFromInstallationData(IEngineInstallationData engineInstallationData, CancellationToken cancellationToken) { if (engineInstallationData is ZipStreamEngineInstallationData zipStreamData) return (MemoryStream)zipStreamData.GetType().GetField("zipStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData); @@ -44,7 +44,15 @@ public static async ValueTask ExtractMemoryStreamFromInstallationD try { await repoData.ExtractToPath(tempFolder, cancellationToken); - var resultStream = new MemoryStream(); + var resultStream = new FileStream( + $"{tempFolder}.zip", + FileMode.Create, + FileAccess.ReadWrite, + FileShare.Read | FileShare.Delete, + 4096, + FileOptions.Asynchronous); + + File.Delete(resultStream.Name); // now we have a ghost file that will delete when the stream closes try { ZipFile.CreateFromDirectory(tempFolder, resultStream, CompressionLevel.NoCompression, false); From bf021d58fd11da36ab37360b4991d699349ad92b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 22:48:29 -0400 Subject: [PATCH 065/717] ADHD telling me to remove this period --- .../Components/Engine/WindowsOpenDreamInstaller.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index 20162e432e5..3614f20ba74 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -78,7 +78,7 @@ protected override async ValueTask HandleExtremelyLongPathOperation(Func Date: Sat, 14 Oct 2023 22:51:30 -0400 Subject: [PATCH 066/717] Fix `OpenDreamInstallation` constructor Actually assign the `Version` property --- .../Components/Engine/OpenDreamInstallation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index 6d1fc3377a4..1ce5e73dae8 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -49,7 +49,7 @@ public OpenDreamInstallation( ServerExePath = serverExePath ?? throw new ArgumentNullException(nameof(serverExePath)); CompilerExePath = compilerExePath ?? throw new ArgumentNullException(nameof(compilerExePath)); InstallationTask = installationTask ?? throw new ArgumentNullException(nameof(installationTask)); - ArgumentNullException.ThrowIfNull(version); + Version = version ?? throw new ArgumentNullException(nameof(version)); if (version.Engine.Value != EngineType.OpenDream) throw new ArgumentException($"Invalid EngineType: {version.Engine.Value}", nameof(version)); From 4e78b3e230943d0238fdd8f430df791370c2638d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 23:00:17 -0400 Subject: [PATCH 067/717] Fix `CustomIteration` not being set for OD engines --- .../Components/Engine/EngineManager.cs | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index 0b7367076d9..f7dbd41fa51 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -381,18 +381,18 @@ await ValueTaskExtensions.WhenAll( public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; /// - /// Ensures a BYOND is installed if it isn't already. + /// Ensures a BYOND is installed if it isn't already. /// /// The optional for the operation. - /// The to install. + /// The to install. /// Custom zip file to use. Will cause a number to be added. /// If this BYOND version is required as part of a locking operation. - /// If an installation should be performed if the is not installed. If and an installation is required an will be thrown. + /// If an installation should be performed if the is not installed. If and an installation is required an will be thrown. /// The for the operation. /// A resulting in the . async ValueTask AssertAndLockVersion( JobProgressReporter progressReporter, - ByondVersion byondVersion, + ByondVersion version, Stream customVersionStream, bool neededForLock, bool allowInstallation, @@ -402,28 +402,27 @@ async ValueTask AssertAndLockVersion( IEngineInstallation installation; EngineExecutableLock installLock; bool installedOrInstalling; - var byondEngine = byondVersion.Engine.Value == EngineType.Byond; lock (installedVersions) { - if (customVersionStream != null && byondEngine) + if (customVersionStream != null) { var customInstallationNumber = 1; do { - byondVersion.CustomIteration = customInstallationNumber++; + version.CustomIteration = customInstallationNumber++; } - while (installedVersions.ContainsKey(byondVersion)); + while (installedVersions.ContainsKey(version)); } - installedOrInstalling = installedVersions.TryGetValue(byondVersion, out var installationContainer); + installedOrInstalling = installedVersions.TryGetValue(version, out var installationContainer); if (!installedOrInstalling) { if (!allowInstallation) - throw new InvalidOperationException($"BYOND version {byondVersion} not installed!"); + throw new InvalidOperationException($"Engine version {version} not installed!"); installationContainer = AddInstallationContainer( - byondVersion, - ioManager.ResolvePath(byondVersion.ToString()), + version, + ioManager.ResolvePath(version.ToString()), ourTcs.Task); } @@ -439,7 +438,7 @@ async ValueTask AssertAndLockVersion( progressReporter.StageName = "Waiting for existing installation job..."; if (neededForLock && !installation.InstallationTask.IsCompleted) - logger.LogWarning("The required BYOND version ({version}) is not readily available! We will have to wait for it to install.", byondVersion); + logger.LogWarning("The required engine version ({version}) is not readily available! We will have to wait for it to install.", version); await installation.InstallationTask.WaitAsync(cancellationToken); return installLock; @@ -449,24 +448,24 @@ async ValueTask AssertAndLockVersion( try { if (customVersionStream != null) - logger.LogInformation("Installing custom BYOND version as {version}...", byondVersion); + logger.LogInformation("Installing custom engine version as {version}...", version); else if (neededForLock) { - if (byondEngine && byondVersion.CustomIteration.HasValue) + if (version.CustomIteration.HasValue) throw new JobException(ErrorCode.EngineNonExistentCustomVersion); - logger.LogWarning("The required BYOND version ({version}) is not readily available! We will have to install it.", byondVersion); + logger.LogWarning("The required engine version ({version}) is not readily available! We will have to install it.", version); } else - logger.LogDebug("Requested BYOND version {version} not currently installed. Doing so now...", byondVersion); + logger.LogDebug("Requested engine version {version} not currently installed. Doing so now...", version); if (progressReporter != null) progressReporter.StageName = "Running event"; - var versionString = byondVersion.ToString(); + var versionString = version.ToString(); await eventConsumer.HandleEvent(EventType.ByondInstallStart, new List { versionString }, false, cancellationToken); - await InstallVersionFiles(progressReporter, byondVersion, customVersionStream, cancellationToken); + await InstallVersionFiles(progressReporter, version, customVersionStream, cancellationToken); ourTcs.SetResult(); } @@ -476,7 +475,7 @@ async ValueTask AssertAndLockVersion( await eventConsumer.HandleEvent(EventType.ByondInstallFail, new List { ex.Message }, false, cancellationToken); lock (installedVersions) - installedVersions.Remove(byondVersion); + installedVersions.Remove(version); ourTcs.SetException(ex); throw; From b8b9ad1e35463b08388f050c037652d93fe79dc7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 23:11:03 -0400 Subject: [PATCH 068/717] Fix BYOND specific `WatchdogTest` asserts --- .../Live/Instance/WatchdogTest.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index c0f3f52ed8d..2c915d0dd13 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -95,9 +95,17 @@ async Task CheckByondVersions() var byondVersion = list[0]; Assert.AreEqual(1, byondVersion.Version.CustomIteration); - Assert.AreEqual(testVersion.Version.Major, byondVersion.Version.Version.Major); - Assert.AreEqual(testVersion.Version.Minor, byondVersion.Version.Version.Minor); Assert.AreEqual(testVersion.Engine, byondVersion.Version.Engine); + if (testVersion.Version != null) + { + Assert.AreEqual(testVersion.Version.Major, byondVersion.Version.Version.Major); + Assert.AreEqual(testVersion.Version.Minor, byondVersion.Version.Version.Minor); + } + else + { + Assert.IsNull(byondVersion.Version.Version); + Assert.AreEqual(testVersion.SourceSHA, byondVersion.Version.SourceSHA); + } } await Task.WhenAll( From 0f038977ebe428e6430153d4ab8927b85e306a2f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 23:11:28 -0400 Subject: [PATCH 069/717] Fix using wrong OD `DMCompiler.exe` --- .../Components/Engine/OpenDreamInstaller.cs | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 1aa0bec4ec0..4857dc4c021 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -24,9 +24,14 @@ namespace Tgstation.Server.Host.Components.Engine class OpenDreamInstaller : EngineInstallerBase { /// - /// The name of the subdirectory used to store the server and compiler binaries. + /// The name of the subdirectory used to store the server binaries. /// - const string InstallationBinDirectory = "bin"; + const string InstallationServerDirectory = "server"; + + /// + /// The name of the subdirectory used to store the compiler binaries. + /// + const string InstallationCompilerDirectory = "compiler"; /// /// The name of the subdirectory used for the 's copy. @@ -226,16 +231,27 @@ await HandleExtremelyLongPathOperation( if (buildExitCode != 0) throw new JobException("OpenDream build failed!"); - await IOManager.MoveDirectory( + var serverMoveTask = IOManager.MoveDirectory( IOManager.ConcatPath( sourcePath, - InstallationBinDirectory, + "bin", "Content.Server"), IOManager.ConcatPath( installPath, - InstallationBinDirectory), + InstallationServerDirectory), + cancellationToken); + + var compilerMoveTask = IOManager.MoveDirectory( + IOManager.ConcatPath( + sourcePath, + "bin", + "DMCompiler"), + IOManager.ConcatPath( + installPath, + InstallationCompilerDirectory), cancellationToken); + await Task.WhenAll(serverMoveTask, compilerMoveTask); await IOManager.DeleteDirectory(sourcePath, cancellationToken); } @@ -275,18 +291,18 @@ protected virtual ValueTask HandleExtremelyLongPathOperation( /// The path to the DMCompiler executable. protected void GetExecutablePaths(string installationPath, out string serverExePath, out string compilerExePath) { - var binPathForVersion = IOManager.ConcatPath(installationPath, InstallationBinDirectory); - var exeExtension = platformIdentifier.IsWindows ? ".exe" : String.Empty; serverExePath = IOManager.ConcatPath( - binPathForVersion, + installationPath, + InstallationServerDirectory, $"OpenDreamServer{exeExtension}"); compilerExePath = IOManager.ConcatPath( - binPathForVersion, + installationPath, + InstallationCompilerDirectory, $"DMCompiler{exeExtension}"); } } From 692c2f60a6388b71f4cd213baf40b739c2f4694e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 14 Oct 2023 23:30:57 -0400 Subject: [PATCH 070/717] Remove --verbose flag from OD compiler invocation --- .../Components/Engine/OpenDreamInstallation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index 1ce5e73dae8..fc0e388366d 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -89,6 +89,6 @@ public string FormatServerArguments(IDmbProvider dmbProvider, IReadOnlyDictionar /// public string FormatCompilerArguments(string dmePath) - => $"--suppress-unimplemented --verbose --notices-enabled {dmePath ?? throw new ArgumentNullException(nameof(dmePath))}"; + => $"--suppress-unimplemented --notices-enabled {dmePath ?? throw new ArgumentNullException(nameof(dmePath))}"; } } From 1416f1817f3a2f7c96e837919a8f95ea7b68900e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 00:00:06 -0400 Subject: [PATCH 071/717] Quote .dme path in OD compiler command line --- .../Components/Engine/OpenDreamInstallation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index fc0e388366d..12c0915402e 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -89,6 +89,6 @@ public string FormatServerArguments(IDmbProvider dmbProvider, IReadOnlyDictionar /// public string FormatCompilerArguments(string dmePath) - => $"--suppress-unimplemented --notices-enabled {dmePath ?? throw new ArgumentNullException(nameof(dmePath))}"; + => $"--suppress-unimplemented --notices-enabled \"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\""; } } From 1eeba3a4b23bc9e05848e2460598b73f9d6cbf23 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 01:49:39 -0400 Subject: [PATCH 072/717] Rename ByondVersion to EngineVersion --- .../{ByondVersion.cs => EngineVersion.cs} | 28 +++++++------- .../Request/ByondVersionDeleteRequest.cs | 2 +- .../Models/Request/ByondVersionRequest.cs | 4 +- .../Models/Response/ByondResponse.cs | 6 +-- .../Models/Response/CompileJobResponse.cs | 6 +-- .../Components/Chat/ChatManager.cs | 4 +- .../Components/Chat/IChatManager.cs | 4 +- .../Chat/Providers/DiscordProvider.cs | 18 ++++----- .../Components/Chat/Providers/IProvider.cs | 4 +- .../Components/Chat/Providers/IrcProvider.cs | 6 +-- .../Components/Chat/Providers/Provider.cs | 2 +- .../Components/Deployment/DmbFactory.cs | 6 +-- .../Components/Deployment/DmbProvider.cs | 8 ++-- .../Components/Deployment/DmbProviderBase.cs | 6 +-- .../Components/Deployment/IDmbProvider.cs | 4 +- .../Deployment/SwappableDmbProvider.cs | 2 +- .../Deployment/TemporaryDmbProvider.cs | 8 ++-- .../Components/Engine/ByondInstallation.cs | 4 +- .../Components/Engine/ByondInstallerBase.cs | 8 ++-- .../Engine/DelegatingEngineInstaller.cs | 12 +++--- .../Components/Engine/EngineExecutableLock.cs | 2 +- .../Components/Engine/EngineInstallerBase.cs | 12 +++--- .../Components/Engine/EngineManager.cs | 38 +++++++++---------- .../Components/Engine/IEngineInstallation.cs | 4 +- .../Components/Engine/IEngineInstaller.cs | 16 ++++---- .../Components/Engine/IEngineManager.cs | 24 ++++++------ .../Engine/OpenDreamInstallation.cs | 4 +- .../Components/Engine/OpenDreamInstaller.cs | 8 ++-- .../Components/Engine/PosixByondInstaller.cs | 4 +- .../Engine/WindowsByondInstaller.cs | 8 ++-- .../Engine/WindowsOpenDreamInstaller.cs | 6 +-- .../Components/Session/ISessionController.cs | 4 +- .../Components/Session/SessionController.cs | 4 +- .../Session/SessionControllerFactory.cs | 6 +-- .../Components/Watchdog/WindowsWatchdog.cs | 4 +- .../Controllers/ByondController.cs | 10 ++--- .../Models/CompileJob.cs | 2 +- .../TestApiClient.cs | 4 +- .../Engine/TestPosixByondInstaller.cs | 4 +- .../CachingFileDownloader.cs | 2 +- .../Live/DummyChatProvider.cs | 4 +- .../Live/Instance/ByondTest.cs | 16 ++++---- .../Live/Instance/InstanceTest.cs | 2 +- .../Live/Instance/WatchdogTest.cs | 4 +- .../Live/TestLiveServer.cs | 2 +- tests/Tgstation.Server.Tests/TestVersions.cs | 18 ++++----- 46 files changed, 177 insertions(+), 177 deletions(-) rename src/Tgstation.Server.Api/Models/Internal/{ByondVersion.cs => EngineVersion.cs} (84%) diff --git a/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs b/src/Tgstation.Server.Api/Models/Internal/EngineVersion.cs similarity index 84% rename from src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs rename to src/Tgstation.Server.Api/Models/Internal/EngineVersion.cs index 297df5df193..65a348b20fb 100644 --- a/src/Tgstation.Server.Api/Models/Internal/ByondVersion.cs +++ b/src/Tgstation.Server.Api/Models/Internal/EngineVersion.cs @@ -8,9 +8,9 @@ namespace Tgstation.Server.Api.Models.Internal { /// - /// Information about a Byond installation. + /// Information about an engine installation. /// - public class ByondVersion : IEquatable + public class EngineVersion : IEquatable { /// /// The . @@ -38,18 +38,18 @@ public class ByondVersion : IEquatable public int? CustomIteration { get; set; } /// - /// Parses a stringified . + /// Parses a stringified . /// /// The input . - /// The output . + /// The output . /// if parsing was successful, otherwise. - public static bool TryParse(string input, out ByondVersion? byondVersion) + public static bool TryParse(string input, out EngineVersion? engineVersion) { if (input == null) throw new ArgumentNullException(nameof(input)); var splits = input.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries); - byondVersion = null; + engineVersion = null; if (splits.Length > 2) return false; @@ -100,7 +100,7 @@ public static bool TryParse(string input, out ByondVersion? byondVersion) } } - byondVersion = new ByondVersion + engineVersion = new EngineVersion { Engine = engine, Version = version, @@ -111,17 +111,17 @@ public static bool TryParse(string input, out ByondVersion? byondVersion) } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public ByondVersion() + public EngineVersion() { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The to copy. - public ByondVersion(ByondVersion other) + /// The to copy. + public EngineVersion(EngineVersion other) { if (other == null) throw new ArgumentNullException(nameof(other)); @@ -133,7 +133,7 @@ public ByondVersion(ByondVersion other) } /// - public bool Equals(ByondVersion other) + public bool Equals(EngineVersion other) { // https://github.com/dotnet/roslyn-analyzers/issues/2875 #pragma warning disable CA1062 // Validate arguments of public methods @@ -149,7 +149,7 @@ public bool Equals(ByondVersion other) /// public override bool Equals(object obj) - => obj is ByondVersion other && Equals(other); + => obj is EngineVersion other && Equals(other); /// public override string ToString() diff --git a/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs b/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs index ad5eac45ccd..3a81b191ccf 100644 --- a/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs @@ -7,7 +7,7 @@ namespace Tgstation.Server.Api.Models.Request /// /// A request to delete a specific . /// - public class ByondVersionDeleteRequest : ByondVersion + public class ByondVersionDeleteRequest : EngineVersion { } } diff --git a/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs b/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs index a7d86f8e79e..c56edecfd66 100644 --- a/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs @@ -3,9 +3,9 @@ namespace Tgstation.Server.Api.Models.Request { /// - /// A request to install a . + /// A request to install a . /// - public sealed class ByondVersionRequest : ByondVersion + public sealed class ByondVersionRequest : EngineVersion { /// /// If a custom BYOND version is to be uploaded. diff --git a/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs b/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs index 0c3d19d4b6a..e289de30a25 100644 --- a/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs @@ -3,13 +3,13 @@ namespace Tgstation.Server.Api.Models.Response { /// - /// Represents an installed . + /// Represents an installed . /// public sealed class ByondResponse { /// - /// The represented . + /// The represented . /// - public ByondVersion? Version { get; set; } + public EngineVersion? Version { get; set; } } } diff --git a/src/Tgstation.Server.Api/Models/Response/CompileJobResponse.cs b/src/Tgstation.Server.Api/Models/Response/CompileJobResponse.cs index a349710f077..b38f11dcc0b 100644 --- a/src/Tgstation.Server.Api/Models/Response/CompileJobResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/CompileJobResponse.cs @@ -18,12 +18,12 @@ public sealed class CompileJobResponse : CompileJob public RevisionInformation? RevisionInformation { get; set; } /// - /// The the was made with. + /// The the was made with. /// - public ByondVersion? ByondVersion { get; set; } + public EngineVersion? ByondVersion { get; set; } /// - /// The the was made with. + /// The the was made with. /// public EngineType? Engine { get; set; } diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index 6bc1ddc015e..d002d606241 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -359,7 +359,7 @@ public void QueueWatchdogMessage(string message) /// public Func> QueueDeploymentMessage( Models.RevisionInformation revisionInformation, - ByondVersion byondVersion, + EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, @@ -389,7 +389,7 @@ public Func> QueueDeploymentMessage( { var callback = await provider.SendUpdateMessage( revisionInformation, - byondVersion, + engineVersion, estimatedCompletionTime, gitHubOwner, gitHubRepo, diff --git a/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs index 3f21930cf5a..41ca31f5c54 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs @@ -61,7 +61,7 @@ public interface IChatManager : IComponentService, IAsyncDisposable /// Send the message for a deployment to configured deployment channels. /// /// The of the deployment. - /// The of the deployment. + /// The of the deployment. /// The optional the deployment is expected to be completed at. /// The repository GitHub owner, if any. /// The repository GitHub name, if any. @@ -69,7 +69,7 @@ public interface IChatManager : IComponentService, IAsyncDisposable /// A to call to update the message at the deployment's conclusion. Parameters: Error message if any, DreamMaker output if any. Returns an to call to mark the deployment as active/inactive. Parameter: If the deployment is being activated or inactivated. Func> QueueDeploymentMessage( Models.RevisionInformation revisionInformation, - ByondVersion byondVersion, + EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 57292f224ac..7737c33f3ac 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -286,7 +286,7 @@ await ValueTaskExtensions.WhenAll( /// public override async ValueTask>>> SendUpdateMessage( Models.RevisionInformation revisionInformation, - ByondVersion byondVersion, + EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, @@ -295,13 +295,13 @@ public override async ValueTask> GetGuildChannels(IPartialGuild guild) /// Create a of s for a discord update embed. /// /// The of the deployment. - /// The of the deployment. + /// The of the deployment. /// The repository GitHub owner, if any. /// The repository GitHub name, if any. /// if the local deployment commit was pushed to the remote repository. /// A new of s to use. List BuildUpdateEmbedFields( Models.RevisionInformation revisionInformation, - ByondVersion byondVersion, + EngineVersion engineVersion, string gitHubOwner, string gitHubRepo, bool localCommitPushed) { bool gitHub = gitHubOwner != null && gitHubRepo != null; - var engineField = byondVersion.Engine.Value switch + var engineField = engineVersion.Engine.Value switch { EngineType.Byond => new EmbedField( "BYOND Version", - $"{byondVersion.Version.Major}.{byondVersion.Version.Minor}{(byondVersion.CustomIteration.HasValue ? $".{byondVersion.CustomIteration.Value}" : String.Empty)}", + $"{engineVersion.Version.Major}.{engineVersion.Version.Minor}{(engineVersion.CustomIteration.HasValue ? $".{engineVersion.CustomIteration.Value}" : String.Empty)}", true), EngineType.OpenDream => new EmbedField( "OpenDream Version", - $"[{byondVersion.SourceSHA[..7]}]({generalConfiguration.OpenDreamGitUrl}/commit/{byondVersion.SourceSHA})", + $"[{engineVersion.SourceSHA[..7]}]({generalConfiguration.OpenDreamGitUrl}/commit/{engineVersion.SourceSHA})", true), - _ => throw new InvalidOperationException($"Invaild EngineType: {byondVersion.Engine.Value}"), + _ => throw new InvalidOperationException($"Invaild EngineType: {engineVersion.Engine.Value}"), }; var fields = new List diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs index 489d8f42880..710559c2777 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs @@ -84,7 +84,7 @@ interface IProvider : IAsyncDisposable /// Send the message for a deployment. /// /// The of the deployment. - /// The of the deployment. + /// The of the deployment. /// The optional the deployment is expected to be completed at. /// The repository GitHub owner, if any. /// The repository GitHub name, if any. @@ -94,7 +94,7 @@ interface IProvider : IAsyncDisposable /// A resulting in a to call to update the message at the deployment's conclusion. Parameters: Error message if any, DreamMaker output if any. Returns another callback which should be called to mark the deployment as active. ValueTask>>> SendUpdateMessage( Models.RevisionInformation revisionInformation, - ByondVersion byondVersion, + EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index 7cf73595c5b..b13c12f6e74 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -221,7 +221,7 @@ await Task.Factory.StartNew( /// public override async ValueTask>>> SendUpdateMessage( Models.RevisionInformation revisionInformation, - ByondVersion byondVersion, + EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, @@ -230,7 +230,7 @@ public override async ValueTask public abstract ValueTask>>> SendUpdateMessage( Models.RevisionInformation revisionInformation, - ByondVersion byondVersion, + EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs index e5e361299b8..c2570119d53 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs @@ -245,7 +245,7 @@ await databaseContextFactory.UseContext( .ThenInclude(x => x.MergedBy) .FirstAsync(cancellationToken)); // can't wait to see that query - if (!Api.Models.Internal.ByondVersion.TryParse(compileJob.ByondVersion, out var byondVersion)) + if (!Api.Models.Internal.EngineVersion.TryParse(compileJob.ByondVersion, out var engineVersion)) { logger.LogWarning("Error loading compile job, bad BYOND version: {0}", compileJob.ByondVersion); return null; // omae wa mou shinderu @@ -268,7 +268,7 @@ void CleanupAction() CleanRegisteredCompileJob(compileJob); } - var newProvider = new DmbProvider(compileJob, byondVersion, ioManager, CleanupAction); + var newProvider = new DmbProvider(compileJob, engineVersion, ioManager, CleanupAction); try { const string LegacyADirectoryName = "A"; @@ -305,7 +305,7 @@ void CleanupAction() // rebuild the provider because it's using the legacy style directories // Don't dispose it logger.LogDebug("Creating legacy two folder .dmb provider targeting {aDirName} directory...", LegacyADirectoryName); - newProvider = new DmbProvider(compileJob, byondVersion, ioManager, CleanupAction, Path.DirectorySeparatorChar + LegacyADirectoryName); + newProvider = new DmbProvider(compileJob, engineVersion, ioManager, CleanupAction, Path.DirectorySeparatorChar + LegacyADirectoryName); } lock (jobLockCounts) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs index 2b58ba17c0b..c9a84dfb3b2 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs @@ -15,7 +15,7 @@ sealed class DmbProvider : DmbProviderBase, IDmbProvider public override Models.CompileJob CompileJob { get; } /// - public override ByondVersion ByondVersion { get; } + public override EngineVersion EngineVersion { get; } /// /// The for the . @@ -36,14 +36,14 @@ sealed class DmbProvider : DmbProviderBase, IDmbProvider /// Initializes a new instance of the class. /// /// The value of . - /// The value of . + /// The value of . /// The value of . /// The value of . /// The optional value of . - public DmbProvider(Models.CompileJob compileJob, ByondVersion byondVersion, IIOManager ioManager, Action onDispose, string directoryAppend = null) + public DmbProvider(Models.CompileJob compileJob, EngineVersion engineVersion, IIOManager ioManager, Action onDispose, string directoryAppend = null) { CompileJob = compileJob ?? throw new ArgumentNullException(nameof(compileJob)); - ByondVersion = byondVersion ?? throw new ArgumentNullException(nameof(byondVersion)); + EngineVersion = engineVersion ?? throw new ArgumentNullException(nameof(engineVersion)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.onDispose = onDispose ?? throw new ArgumentNullException(nameof(onDispose)); this.directoryAppend = directoryAppend ?? String.Empty; diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs index ea792bd23d5..9e949d29198 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs @@ -12,11 +12,11 @@ abstract class DmbProviderBase : IDmbProvider /// public string DmbName => String.Concat( CompileJob.DmeName, - ByondVersion.Engine.Value switch + EngineVersion.Engine.Value switch { EngineType.Byond => ".dmb", EngineType.OpenDream => ".json", - _ => throw new InvalidOperationException($"Invalid EngineType: {ByondVersion.Engine.Value}"), + _ => throw new InvalidOperationException($"Invalid EngineType: {EngineVersion.Engine.Value}"), }); /// @@ -26,7 +26,7 @@ abstract class DmbProviderBase : IDmbProvider public abstract Models.CompileJob CompileJob { get; } /// - public abstract ByondVersion ByondVersion { get; } + public abstract EngineVersion EngineVersion { get; } /// public abstract void Dispose(); diff --git a/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs index 8f81cb7fbc1..3a20614ca71 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs @@ -25,9 +25,9 @@ public interface IDmbProvider : IDisposable Models.CompileJob CompileJob { get; } /// - /// The used to build the .dmb. + /// The used to build the .dmb. /// - ByondVersion ByondVersion { get; } + EngineVersion EngineVersion { get; } /// /// Disposing the won't cause a cleanup of the working directory. diff --git a/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs index cfa69ede089..e2bf9e61544 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs @@ -27,7 +27,7 @@ sealed class SwappableDmbProvider : IDmbProvider public Models.CompileJob CompileJob => baseProvider.CompileJob; /// - public ByondVersion ByondVersion => baseProvider.ByondVersion; + public EngineVersion EngineVersion => baseProvider.EngineVersion; /// /// If has been run. diff --git a/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs index a94efe35ed4..52166b39320 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs @@ -16,19 +16,19 @@ sealed class TemporaryDmbProvider : DmbProviderBase public override Models.CompileJob CompileJob { get; } /// - public override ByondVersion ByondVersion { get; } + public override EngineVersion EngineVersion { get; } /// /// Initializes a new instance of the class. /// /// The value of . /// The value of . - /// The value of . - public TemporaryDmbProvider(string directory, Models.CompileJob compileJob, ByondVersion byondVersion) + /// The value of . + public TemporaryDmbProvider(string directory, Models.CompileJob compileJob, EngineVersion engineVersion) { Directory = directory ?? throw new ArgumentNullException(nameof(directory)); CompileJob = compileJob ?? throw new ArgumentNullException(nameof(compileJob)); - ByondVersion = byondVersion ?? throw new ArgumentNullException(nameof(byondVersion)); + EngineVersion = engineVersion ?? throw new ArgumentNullException(nameof(engineVersion)); } /// diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs index 81156de45bd..780fc91a5ab 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs @@ -17,7 +17,7 @@ namespace Tgstation.Server.Host.Components.Engine sealed class ByondInstallation : IEngineInstallation { /// - public ByondVersion Version { get; } + public EngineVersion Version { get; } /// public string ServerExePath { get; } @@ -82,7 +82,7 @@ static string VisibilityWord(DreamDaemonVisibility visibility) /// The value of . public ByondInstallation( Task installationTask, - ByondVersion version, + EngineVersion version, string dreamDaemonPath, string dreamMakerPath, bool supportsCli, diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index 68111c3e99e..c465feb1df1 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -85,7 +85,7 @@ protected ByondInstallerBase(IIOManager ioManager, ILogger l } /// - public override IEngineInstallation CreateInstallation(ByondVersion version, string path, Task installationTask) + public override IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask) { CheckVersionValidity(version); @@ -198,7 +198,7 @@ public override async ValueTask TrustDmbPath(string fullDmbPath, CancellationTok } /// - public override async ValueTask DownloadVersion(ByondVersion version, JobProgressReporter progressReporter, CancellationToken cancellationToken) + public override async ValueTask DownloadVersion(EngineVersion version, JobProgressReporter progressReporter, CancellationToken cancellationToken) { CheckVersionValidity(version); @@ -234,10 +234,10 @@ public override async ValueTask DownloadVersion(ByondVe /// /// Create a pointing to the location of the download for a given . /// - /// The to create a for. + /// The to create a for. /// The for the operation. /// A resulting in a new pointing to the version download location. - ValueTask GetDownloadZipUrl(ByondVersion version, CancellationToken cancellationToken) + ValueTask GetDownloadZipUrl(EngineVersion version, CancellationToken cancellationToken) { CheckVersionValidity(version); var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Version.Major, version.Version.Minor); diff --git a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs index 652a2e55fac..ec8e7267c38 100644 --- a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs @@ -35,15 +35,15 @@ public Task CleanCache(CancellationToken cancellationToken) => Task.WhenAll(delegatedInstallers.Values.Select(installer => installer.CleanCache(cancellationToken))); /// - public IEngineInstallation CreateInstallation(ByondVersion version, string path, Task installationTask) + public IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask) => DelegateCall(version, installer => installer.CreateInstallation(version, path, installationTask)); /// - public ValueTask DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken) + public ValueTask DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken) => DelegateCall(version, installer => installer.DownloadVersion(version, jobProgressReporter, cancellationToken)); /// - public ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken) + public ValueTask Install(EngineVersion version, string path, CancellationToken cancellationToken) => DelegateCall(version, installer => installer.Install(version, path, cancellationToken)); /// @@ -51,17 +51,17 @@ public ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellation => ValueTaskExtensions.WhenAll(delegatedInstallers.Values.Select(installer => installer.TrustDmbPath(fullDmbPath, cancellationToken))); /// - public ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken) + public ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken) => DelegateCall(version, installer => installer.UpgradeInstallation(version, path, cancellationToken)); /// /// Delegate a given to its appropriate . /// /// The return of the call. - /// The used to perform delegate selection. + /// The used to perform delegate selection. /// The that will be called with the correct based on . /// The value of the delegated call. - TReturn DelegateCall(ByondVersion version, Func call) + TReturn DelegateCall(EngineVersion version, Func call) { ArgumentNullException.ThrowIfNull(version); return call(delegatedInstallers[version.Engine.Value]); diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs index 3fd50f4c853..6ef921aaa73 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs @@ -11,7 +11,7 @@ namespace Tgstation.Server.Host.Components.Engine sealed class EngineExecutableLock : ReferenceCounter, IEngineExecutableLock { /// - public ByondVersion Version => Instance.Version; + public EngineVersion Version => Instance.Version; /// public string ServerExePath => Instance.ServerExePath; diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs index ded8a8c75f9..9f1be75dd25 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs @@ -41,19 +41,19 @@ protected EngineInstallerBase(IIOManager ioManager, ILogger } /// - public abstract IEngineInstallation CreateInstallation(ByondVersion version, string path, Task installationTask); + public abstract IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask); /// public abstract Task CleanCache(CancellationToken cancellationToken); /// - public abstract ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken); + public abstract ValueTask Install(EngineVersion version, string path, CancellationToken cancellationToken); /// - public abstract ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken); + public abstract ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken); /// - public abstract ValueTask DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken); + public abstract ValueTask DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken); /// public abstract ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken); @@ -61,8 +61,8 @@ protected EngineInstallerBase(IIOManager ioManager, ILogger /// /// Check that a given is of type . /// - /// The to check. - protected void CheckVersionValidity(ByondVersion version) + /// The to check. + protected void CheckVersionValidity(EngineVersion version) { ArgumentNullException.ThrowIfNull(version); if (version.Engine.Value != TargetEngineType) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index f7dbd41fa51..3a1097bd89b 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -33,10 +33,10 @@ sealed class EngineManager : IEngineManager const string ActiveVersionFileName = "ActiveVersion.txt"; /// - public ByondVersion ActiveVersion { get; private set; } + public EngineVersion ActiveVersion { get; private set; } /// - public IReadOnlyList InstalledVersions + public IReadOnlyList InstalledVersions { get { @@ -66,9 +66,9 @@ public IReadOnlyList InstalledVersions readonly ILogger logger; /// - /// Map of byond s to s that complete when they are installed. + /// Map of byond s to s that complete when they are installed. /// - readonly Dictionary> installedVersions; + readonly Dictionary> installedVersions; /// /// The for changing or deleting the active BYOND version. @@ -84,7 +84,7 @@ public IReadOnlyList InstalledVersions /// Validates a given parameter. /// /// The to validate. - static void CheckVersionParameter(ByondVersion version) + static void CheckVersionParameter(EngineVersion version) { ArgumentNullException.ThrowIfNull(version); @@ -109,7 +109,7 @@ public EngineManager(IIOManager ioManager, IEngineInstaller engineInstaller, IEv this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - installedVersions = new Dictionary>(); + installedVersions = new Dictionary>(); changeDeleteSemaphore = new SemaphoreSlim(1); activeVersionChanged = new TaskCompletionSource(); } @@ -120,7 +120,7 @@ public EngineManager(IIOManager ioManager, IEngineInstaller engineInstaller, IEv /// public async ValueTask ChangeVersion( JobProgressReporter progressReporter, - ByondVersion version, + EngineVersion version, Stream customVersionStream, bool allowInstallation, CancellationToken cancellationToken) @@ -138,7 +138,7 @@ public async ValueTask ChangeVersion( cancellationToken); // We reparse the version because it could be changed after a custom install. - version = new ByondVersion(installLock.Version); + version = new EngineVersion(installLock.Version); var stringVersion = version.ToString(); await ioManager.WriteAllBytes(ActiveVersionFileName, Encoding.UTF8.GetBytes(stringVersion), cancellationToken); @@ -161,7 +161,7 @@ await eventConsumer.HandleEvent( } /// - public async ValueTask UseExecutables(ByondVersion requiredVersion, string trustDmbFullPath, CancellationToken cancellationToken) + public async ValueTask UseExecutables(EngineVersion requiredVersion, string trustDmbFullPath, CancellationToken cancellationToken) { logger.LogTrace( "Acquiring lock on BYOND version {version}...", @@ -189,7 +189,7 @@ public async ValueTask UseExecutables(ByondVersion requir } /// - public async ValueTask DeleteVersion(JobProgressReporter progressReporter, ByondVersion version, CancellationToken cancellationToken) + public async ValueTask DeleteVersion(JobProgressReporter progressReporter, EngineVersion version, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(progressReporter); @@ -306,7 +306,7 @@ async ValueTask GetActiveVersion() await ioManager.CreateDirectory(DefaultIOManager.CurrentDirectory, cancellationToken); var directories = await ioManager.GetDirectories(DefaultIOManager.CurrentDirectory, cancellationToken); - var installedVersionPaths = new Dictionary(); + var installedVersionPaths = new Dictionary(); async ValueTask ReadVersion(string path) { @@ -320,7 +320,7 @@ async ValueTask ReadVersion(string path) var bytes = await ioManager.ReadAllBytes(versionFile, cancellationToken); var text = Encoding.UTF8.GetString(bytes); - if (!ByondVersion.TryParse(text, out var version)) + if (!EngineVersion.TryParse(text, out var version)) { logger.LogWarning("Cleaning path with unparsable version file: {versionPath}", ioManager.ResolvePath(path)); await ioManager.DeleteDirectory(path, cancellationToken); // cleanup @@ -361,10 +361,10 @@ await ValueTaskExtensions.WhenAll( { var activeVersionString = Encoding.UTF8.GetString(activeVersionBytes); - ByondVersion activeVersion; + EngineVersion activeVersion; bool hasRequestedActiveVersion; lock (installedVersions) - hasRequestedActiveVersion = ByondVersion.TryParse(activeVersionString, out activeVersion) + hasRequestedActiveVersion = EngineVersion.TryParse(activeVersionString, out activeVersion) && installedVersions.ContainsKey(activeVersion); if (hasRequestedActiveVersion) @@ -384,7 +384,7 @@ await ValueTaskExtensions.WhenAll( /// Ensures a BYOND is installed if it isn't already. /// /// The optional for the operation. - /// The to install. + /// The to install. /// Custom zip file to use. Will cause a number to be added. /// If this BYOND version is required as part of a locking operation. /// If an installation should be performed if the is not installed. If and an installation is required an will be thrown. @@ -392,7 +392,7 @@ await ValueTaskExtensions.WhenAll( /// A resulting in the . async ValueTask AssertAndLockVersion( JobProgressReporter progressReporter, - ByondVersion version, + EngineVersion version, Stream customVersionStream, bool neededForLock, bool allowInstallation, @@ -494,11 +494,11 @@ async ValueTask AssertAndLockVersion( /// Installs the files for a given BYOND . /// /// The optional for the operation. - /// The being installed with the number set if appropriate. + /// The being installed with the number set if appropriate. /// Custom zip file to use. Will cause a number to be added. /// The for the operation. /// A representing the running operation. - async ValueTask InstallVersionFiles(JobProgressReporter progressReporter, ByondVersion version, Stream customVersionStream, CancellationToken cancellationToken) + async ValueTask InstallVersionFiles(JobProgressReporter progressReporter, EngineVersion version, Stream customVersionStream, CancellationToken cancellationToken) { var installFullPath = ioManager.ResolvePath(version.ToString()); async ValueTask DirectoryCleanup() @@ -578,7 +578,7 @@ await ioManager.WriteAllBytes( /// The path to the installation. /// The representing the installation process. /// The new . - ReferenceCountingContainer AddInstallationContainer(ByondVersion version, string installPath, Task installationTask) + ReferenceCountingContainer AddInstallationContainer(EngineVersion version, string installPath, Task installationTask) { var installation = engineInstaller.CreateInstallation(version, installPath, installationTask); diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs index 238b4fea117..aa43847ae2d 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs @@ -12,9 +12,9 @@ namespace Tgstation.Server.Host.Components.Engine public interface IEngineInstallation { /// - /// The of the . + /// The of the . /// - ByondVersion Version { get; } + EngineVersion Version { get; } /// /// The full path to the game server executable. diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs index e7ef6a41502..bd59169206e 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs @@ -14,38 +14,38 @@ interface IEngineInstaller /// /// Creates an for a given . /// - /// The of the installation. + /// The of the installation. /// The path to the installation. /// The representing the installation process for the installation. /// The . - IEngineInstallation CreateInstallation(ByondVersion version, string path, Task installationTask); + IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask); /// /// Download a given engine . /// - /// The of the engine to download. + /// The of the engine to download. /// The optional for the operation. /// The for the operation. /// A resulting in the for the download. - ValueTask DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken); + ValueTask DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken); /// /// Does actions necessary to get an extracted installation working. /// - /// The being installed. + /// The being installed. /// The path to the installation. /// The for the operation. /// A representing the running operation. - ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken); + ValueTask Install(EngineVersion version, string path, CancellationToken cancellationToken); /// /// Does actions necessary to get upgrade a version installed by a previous version of TGS. /// - /// The being installed. + /// The being installed. /// The path to the installation. /// The for the operation. /// A representing the running operation. - ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken); + ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken); /// /// Add a given to the trusted DMBs list in BYOND's config. diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs index 1951fbc4bc9..f4be62af6c6 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs @@ -13,31 +13,31 @@ namespace Tgstation.Server.Host.Components.Engine /// /// For managing the engine installations. /// - /// When passing in s for , ensure they are BYOND format versions unless referring to a custom version. This means should NEVER be 0. + /// When passing in s for , ensure they are BYOND format versions unless referring to a custom version. This means should NEVER be 0. public interface IEngineManager : IComponentService, IDisposable { /// - /// The currently active . + /// The currently active . /// - ByondVersion ActiveVersion { get; } + EngineVersion ActiveVersion { get; } /// - /// The installed s. + /// The installed s. /// - IReadOnlyList InstalledVersions { get; } + IReadOnlyList InstalledVersions { get; } /// - /// Change the active . + /// Change the active . /// /// The optional for the operation. - /// The new . + /// The new . /// Optional of a custom BYOND version zip file. /// If an installation should be performed if the is not installed. If and an installation is required an will be thrown. /// The for the operation. /// A representing the running operation. ValueTask ChangeVersion( JobProgressReporter progressReporter, - ByondVersion version, + EngineVersion version, Stream customVersionStream, bool allowInstallation, CancellationToken cancellationToken); @@ -46,20 +46,20 @@ ValueTask ChangeVersion( /// Deletes a given from the disk. /// /// The for the operation. - /// The to delete. + /// The to delete. /// The for the operation. /// A representing the running operation. - ValueTask DeleteVersion(JobProgressReporter progressReporter, ByondVersion version, CancellationToken cancellationToken); + ValueTask DeleteVersion(JobProgressReporter progressReporter, EngineVersion version, CancellationToken cancellationToken); /// /// Lock the current installation's location and return a . /// - /// The required. + /// The required. /// The optional full path to .dmb to trust while using the executables. /// The for the operation. /// A resulting in the requested . ValueTask UseExecutables( - ByondVersion requiredVersion, + EngineVersion requiredVersion, string trustDmbFullPath, CancellationToken cancellationToken); } diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index 12c0915402e..66a2e11b9dd 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -16,7 +16,7 @@ namespace Tgstation.Server.Host.Components.Engine sealed class OpenDreamInstallation : IEngineInstallation { /// - public ByondVersion Version { get; } + public EngineVersion Version { get; } /// public string ServerExePath { get; } @@ -44,7 +44,7 @@ public OpenDreamInstallation( string serverExePath, string compilerExePath, Task installationTask, - ByondVersion version) + EngineVersion version) { ServerExePath = serverExePath ?? throw new ArgumentNullException(nameof(serverExePath)); CompilerExePath = compilerExePath ?? throw new ArgumentNullException(nameof(compilerExePath)); diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 4857dc4c021..cd6cd5eeb76 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -89,7 +89,7 @@ public OpenDreamInstaller( public override Task CleanCache(CancellationToken cancellationToken) => Task.CompletedTask; /// - public override IEngineInstallation CreateInstallation(ByondVersion version, string path, Task installationTask) + public override IEngineInstallation CreateInstallation(EngineVersion version, string path, Task installationTask) { CheckVersionValidity(version); GetExecutablePaths(path, out var serverExePath, out var compilerExePath); @@ -101,7 +101,7 @@ public override IEngineInstallation CreateInstallation(ByondVersion version, str } /// - public override async ValueTask DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken) + public override async ValueTask DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken) { CheckVersionValidity(version); @@ -157,7 +157,7 @@ await repo.CheckoutObject( } /// - public override async ValueTask Install(ByondVersion version, string installPath, CancellationToken cancellationToken) + public override async ValueTask Install(EngineVersion version, string installPath, CancellationToken cancellationToken) { CheckVersionValidity(version); ArgumentNullException.ThrowIfNull(installPath); @@ -256,7 +256,7 @@ await HandleExtremelyLongPathOperation( } /// - public override ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken) + public override ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken) { CheckVersionValidity(version); ArgumentNullException.ThrowIfNull(path); diff --git a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs index ed3785cfbd2..e82b3f133dc 100644 --- a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs @@ -70,7 +70,7 @@ public PosixByondInstaller( } /// - public override ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken) + public override ValueTask Install(EngineVersion version, string path, CancellationToken cancellationToken) { CheckVersionValidity(version); ArgumentNullException.ThrowIfNull(path); @@ -110,7 +110,7 @@ async ValueTask WriteAndMakeExecutable(string pathToScript, string script) } /// - public override ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken) + public override ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken) { CheckVersionValidity(version); ArgumentNullException.ThrowIfNull(path); diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 60077b006b1..3c5b44f0975 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -115,7 +115,7 @@ public WindowsByondInstaller( public void Dispose() => semaphore.Dispose(); /// - public override ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken) + public override ValueTask Install(EngineVersion version, string path, CancellationToken cancellationToken) { CheckVersionValidity(version); ArgumentNullException.ThrowIfNull(path); @@ -133,7 +133,7 @@ public override ValueTask Install(ByondVersion version, string path, Cancellatio } /// - public override async ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken) + public override async ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken) { CheckVersionValidity(version); ArgumentNullException.ThrowIfNull(path); @@ -224,11 +224,11 @@ async ValueTask InstallDirectX(string path, CancellationToken cancellationToken) /// /// Attempt to add the DreamDaemon executable as an exception to the Windows firewall. /// - /// The BYOND . + /// The BYOND . /// The path to the BYOND installation. /// The for the operation. /// A representing the running operation. - async ValueTask AddDreamDaemonToFirewall(ByondVersion version, string path, CancellationToken cancellationToken) + async ValueTask AddDreamDaemonToFirewall(EngineVersion version, string path, CancellationToken cancellationToken) { var dreamDaemonName = GetDreamDaemonName(version.Version, out var usesDDExe); diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index 3614f20ba74..eb31f462faa 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -56,7 +56,7 @@ public WindowsOpenDreamInstaller( } /// - public override ValueTask Install(ByondVersion version, string installPath, CancellationToken cancellationToken) + public override ValueTask Install(EngineVersion version, string installPath, CancellationToken cancellationToken) => ValueTaskExtensions.WhenAll( base.Install( version, @@ -85,11 +85,11 @@ protected override async ValueTask HandleExtremelyLongPathOperation(Func /// Attempt to add the DreamDaemon executable as an exception to the Windows firewall. /// - /// The BYOND . + /// The BYOND . /// The path to the BYOND installation. /// The for the operation. /// A representing the running operation. - async ValueTask AddServerFirewallException(ByondVersion version, string path, CancellationToken cancellationToken) + async ValueTask AddServerFirewallException(EngineVersion version, string path, CancellationToken cancellationToken) { GetExecutablePaths(path, out var serverExePath, out _); diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs index 3082a2d2533..48d08adcc09 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs @@ -40,9 +40,9 @@ interface ISessionController : IProcessBase, IRenameNotifyee, IAsyncDisposable Models.CompileJob CompileJob { get; } /// - /// Gets the associated with the . + /// Gets the associated with the . /// - ByondVersion ByondVersion { get; } + EngineVersion EngineVersion { get; } /// /// Gets the associated with the . diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 2d48efdc410..74b4481562a 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -53,7 +53,7 @@ public ApiValidationStatus ApiValidationStatus public Models.CompileJob CompileJob => ReattachInformation.Dmb.CompileJob; /// - public ByondVersion ByondVersion => ReattachInformation.Dmb.ByondVersion; + public EngineVersion EngineVersion => ReattachInformation.Dmb.EngineVersion; /// public RebootState RebootState => ReattachInformation.RebootState; @@ -660,7 +660,7 @@ async ValueTask ProcessBridgeCommand(BridgeParameters parameters // TODO: When OD figures out how to unite port and topic_port, set an upper version bound on OD for this check if (DMApiVersion.Major != DMApiConstants.InteropVersion.Major - || (ByondVersion.Engine.Value == EngineType.OpenDream && DMApiVersion < new Version(5, 7))) + || (EngineVersion.Engine.Value == EngineType.OpenDream && DMApiVersion < new Version(5, 7))) { apiValidationStatus = ApiValidationStatus.Incompatible; return BridgeError("Incompatible dmApiVersion!"); diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index c2dba13e8c3..1168a37e8a5 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -240,7 +240,7 @@ public async ValueTask LaunchNew( // get the byond lock var byondLock = currentByondLock ?? await engineManager.UseExecutables( - dmbProvider.ByondVersion, + dmbProvider.EngineVersion, gameIOManager.ConcatPath(dmbProvider.Directory, dmbProvider.DmbName), cancellationToken); try @@ -252,7 +252,7 @@ public async ValueTask LaunchNew( PortBindTest(launchParameters.Port.Value); // mad this isn't abstracted but whatever - if (dmbProvider.ByondVersion.Engine.Value == EngineType.Byond) + if (dmbProvider.EngineVersion.Engine.Value == EngineType.Byond) await CheckPagerIsNotRunning(); string outputFilePath = null; @@ -374,7 +374,7 @@ public async ValueTask Reattach( logger.LogTrace("Begin session reattach..."); var byondTopicSender = topicClientFactory.CreateTopicClient(reattachInformation.TopicRequestTimeout); var byondLock = await engineManager.UseExecutables( - reattachInformation.Dmb.ByondVersion, + reattachInformation.Dmb.EngineVersion, null, // Doesn't matter if it's trusted or not on reattach cancellationToken); diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs index af112dae3ef..23acb7885ce 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs @@ -246,8 +246,8 @@ protected override async ValueTask HandleNewDmbAvailable(CancellationToken cance canSeamlesslySwap = false; } - if (Server.ByondVersion.Engine.Value != EngineType.Byond - || compileJobProvider.ByondVersion.Engine.Value != EngineType.Byond) + if (Server.EngineVersion.Engine.Value != EngineType.Byond + || compileJobProvider.EngineVersion.Engine.Value != EngineType.Byond) { Logger.LogDebug( "Not swapping to new compile job {newCompileJobId} as it or the current compile job ({oldCompileJobId}) is not using the BYOND engine. Queueing graceful restart instead...", diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index 45447a2fbf4..c5857f54877 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -83,7 +83,7 @@ public ByondController( } /// - /// Gets the active . + /// Gets the active . /// /// A resulting in the for the operation. /// Retrieved version information successfully. @@ -102,7 +102,7 @@ public ValueTask Read() }))); /// - /// Lists installed s. + /// Lists installed s. /// /// The current page. /// The page size. @@ -275,7 +275,7 @@ await core.EngineManager.ChangeVersion( /// A resulting in the for the operation. /// Created to delete target version successfully. /// Attempted to delete the active BYOND . - /// The specified was not installed. + /// The specified was not installed. [HttpDelete] [TgsAuthorize(ByondRights.DeleteInstall)] [ProducesResponseType(typeof(JobResponse), 202)] @@ -337,9 +337,9 @@ await jobManager.RegisterOperation( /// /// Validate and normalize a given . /// - /// The to validate and normalize. + /// The to validate and normalize. /// The to return, if any. - BadRequestObjectResult ValidateByondVersion(ByondVersion version) + BadRequestObjectResult ValidateByondVersion(EngineVersion version) { ArgumentNullException.ThrowIfNull(version); diff --git a/src/Tgstation.Server.Host/Models/CompileJob.cs b/src/Tgstation.Server.Host/Models/CompileJob.cs index a5f5ac67d04..7f69e618ff8 100644 --- a/src/Tgstation.Server.Host/Models/CompileJob.cs +++ b/src/Tgstation.Server.Host/Models/CompileJob.cs @@ -90,7 +90,7 @@ public override Version DMApiVersion Job = Job.ToApi(), Output = Output, RevisionInformation = RevisionInformation.ToApi(), - ByondVersion = Api.Models.Internal.ByondVersion.TryParse(ByondVersion, out var version) + ByondVersion = Api.Models.Internal.EngineVersion.TryParse(ByondVersion, out var version) ? version : throw new InvalidOperationException($"Failed to parse BYOND version: {ByondVersion}"), MinimumSecurityLevel = MinimumSecurityLevel, diff --git a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs index 9747e8b84f7..0edc228b18e 100644 --- a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs +++ b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs @@ -26,7 +26,7 @@ public async Task TestDeserializingByondModelsWork() { var sample = new ByondResponse { - Version = new ByondVersion + Version = new EngineVersion { Engine = EngineType.Byond, Version = new Version(511, 1385) @@ -60,7 +60,7 @@ public async Task TestUnrecognizedResponse() { var sample = new ByondResponse { - Version = new ByondVersion + Version = new EngineVersion { Engine = EngineType.Byond, Version = new Version(511, 1385) diff --git a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs index c7f117fb7a9..22cc145683a 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestPosixByondInstaller.cs @@ -65,7 +65,7 @@ public async Task TestDownload() new MemoryStream(ourArray))) .Verifiable(); - var result = ExtractMemoryStreamFromInstallationData(await installer.DownloadVersion(new ByondVersion + var result = ExtractMemoryStreamFromInstallationData(await installer.DownloadVersion(new EngineVersion { Engine = EngineType.Byond, Version = new Version(511, 1385), @@ -92,7 +92,7 @@ public async Task TestInstallByond() const string FakePath = "fake"; await Assert.ThrowsExceptionAsync(() => installer.Install(null, null, default).AsTask()); - var byondVersion = new ByondVersion + var byondVersion = new EngineVersion { Engine = EngineType.Byond, Version = new Version(123, 252345), diff --git a/tests/Tgstation.Server.Tests/CachingFileDownloader.cs b/tests/Tgstation.Server.Tests/CachingFileDownloader.cs index e00206bfe0f..4b66154d438 100644 --- a/tests/Tgstation.Server.Tests/CachingFileDownloader.cs +++ b/tests/Tgstation.Server.Tests/CachingFileDownloader.cs @@ -79,7 +79,7 @@ public static async Task InitializeAndInjectForLiveTests(CancellationToken cance public static async ValueTask InitializeByondVersion(ILogger logger, Version byondVersion, bool windows, CancellationToken cancellationToken) { - var version = new ByondVersion + var version = new EngineVersion { Engine = Api.Models.EngineType.Byond, Version = byondVersion, diff --git a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs index 255e162c8d9..88fba0b8bf1 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs @@ -103,7 +103,7 @@ public override ValueTask SendMessage(Message replyTo, MessageContent message, u public override ValueTask>>> SendUpdateMessage( Host.Models.RevisionInformation revisionInformation, - ByondVersion byondVersion, + EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, @@ -112,7 +112,7 @@ public override ValueTask>> CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(revisionInformation); - ArgumentNullException.ThrowIfNull(byondVersion); + ArgumentNullException.ThrowIfNull(engineVersion); ArgumentNullException.ThrowIfNull(gitHubOwner); ArgumentNullException.ThrowIfNull(gitHubRepo); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index 96bd2c09d14..a6525a8d923 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -33,13 +33,13 @@ sealed class ByondTest(IByondClient byondClient, IJobsClient jobsClient, IFileDo readonly Api.Models.Instance metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); - static readonly Dictionary edgeVersions = new () + static readonly Dictionary edgeVersions = new () { { EngineType.Byond, null }, { EngineType.OpenDream, null } }; - ByondVersion testVersion; + EngineVersion testVersion; readonly EngineType testEngine = engineType; public Task Run(CancellationToken cancellationToken, out Task firstInstall) @@ -48,14 +48,14 @@ public Task Run(CancellationToken cancellationToken, out Task firstInstall) return RunContinued(firstInstall, cancellationToken); } - public static async ValueTask GetEdgeVersion(EngineType engineType, IFileDownloader fileDownloader, CancellationToken cancellationToken) + public static async ValueTask GetEdgeVersion(EngineType engineType, IFileDownloader fileDownloader, CancellationToken cancellationToken) { var edgeVersion = edgeVersions[engineType]; if (edgeVersion != null) return edgeVersion; - ByondVersion byondVersion; + EngineVersion engineVersion; if (engineType == EngineType.Byond) { await using var provider = fileDownloader.DownloadFile(new Uri("https://www.byond.com/download/version.txt"), null); @@ -79,13 +79,13 @@ public static async ValueTask GetEdgeVersion(EngineType engineType if (badVersionMap.TryGetValue(targetVersion, out var remappedVersion)) targetVersion = remappedVersion; - Assert.IsTrue(ByondVersion.TryParse(targetVersion, out byondVersion), $"Bad version: {targetVersion}"); + Assert.IsTrue(EngineVersion.TryParse(targetVersion, out engineVersion), $"Bad version: {targetVersion}"); } else if (engineType == EngineType.OpenDream) { var masterBranch = await TestingGitHubService.RealTestClient.Repository.Branch.Get("OpenDreamProject", "OpenDream", "master"); - byondVersion = new ByondVersion + engineVersion = new EngineVersion { Engine = EngineType.OpenDream, SourceSHA = masterBranch.Commit.Sha, @@ -97,8 +97,8 @@ public static async ValueTask GetEdgeVersion(EngineType engineType return null; } - global::System.Console.WriteLine($"Edge {engineType} version evalutated to {byondVersion}"); - return edgeVersions[engineType] = byondVersion; + global::System.Console.WriteLine($"Edge {engineType} version evalutated to {engineVersion}"); + return edgeVersions[engineType] = engineVersion; } async Task RunPartOne(CancellationToken cancellationToken) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 67f2d6ee9bb..d7d1e79b087 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -67,7 +67,7 @@ public async Task RunTests( } public async Task RunCompatTests( - ByondVersion compatVersion, + EngineVersion compatVersion, IInstanceClient instanceClient, ushort dmPort, ushort ddPort, diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 2c915d0dd13..2224e635205 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -58,11 +58,11 @@ sealed class WatchdogTest : JobsRequiredTest readonly ushort ddPort; readonly bool highPrioDD; readonly TopicClient topicClient; - readonly ByondVersion testVersion; + readonly EngineVersion testVersion; bool ranTimeoutTest = false; - public WatchdogTest(ByondVersion testVersion, IInstanceClient instanceClient, InstanceManager instanceManager, ushort serverPort, bool highPrioDD, ushort ddPort) + public WatchdogTest(EngineVersion testVersion, IInstanceClient instanceClient, InstanceManager instanceManager, ushort serverPort, bool highPrioDD, ushort ddPort) : base(instanceClient.Jobs) { this.instanceClient = instanceClient ?? throw new ArgumentNullException(nameof(instanceClient)); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 9f4a7fc72a2..6bf1ccf6c25 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1143,7 +1143,7 @@ await ByondTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellatio ? FailFast( instanceTest .RunCompatTests( - new ByondVersion + new EngineVersion { Engine = EngineType.Byond, Version = new Version(510, 1346) diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 1e5fc87139c..646a362d22e 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -129,7 +129,7 @@ await CachingFileDownloader.InitializeByondVersion( var hasEntry = ArchiveHasFileEntry( await TestingUtils.ExtractMemoryStreamFromInstallationData( await byondInstaller.DownloadVersion( - new ByondVersion + new EngineVersion { Engine = EngineType.Byond, Version = WindowsByondInstaller.DDExeVersion @@ -216,14 +216,14 @@ await CachingFileDownloader.InitializeByondVersion( try { await TestMapThreadsVersion( - new ByondVersion + new EngineVersion { Engine = EngineType.Byond, Version = MapThreadsVersion(), }, await TestingUtils.ExtractMemoryStreamFromInstallationData( await byondInstaller.DownloadVersion( - new ByondVersion + new EngineVersion { Engine = EngineType.Byond, Version = MapThreadsVersion() @@ -406,10 +406,10 @@ static string GetMigrationTimestampString(Type type) => type Assert.AreEqual(latestMigrationSL, DatabaseContext.SLLatestMigration); } - static async Task> GetByondVersionPriorTo(ByondInstallerBase byondInstaller, Version version) + static async Task> GetByondVersionPriorTo(ByondInstallerBase byondInstaller, Version version) { var minusOneMinor = new Version(version.Major, version.Minor - 1); - var byondVersion = new ByondVersion + var byondVersion = new EngineVersion { Engine = EngineType.Byond, Version = minusOneMinor @@ -433,7 +433,7 @@ static async Task> GetByondVersionPriorTo(ByondInsta } static async Task TestMapThreadsVersion( - ByondVersion byondVersion, + EngineVersion engineVersion, Stream byondBytes, ByondInstallerBase byondInstaller, IIOManager ioManager, @@ -448,12 +448,12 @@ static async Task TestMapThreadsVersion( if (byondInstaller is WindowsByondInstaller) typeof(WindowsByondInstaller).GetField("installedDirectX", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(byondInstaller, true); - await byondInstaller.Install(byondVersion, tempPath, default); + await byondInstaller.Install(engineVersion, tempPath, default); var binPath = (string)typeof(ByondInstallerBase).GetField("BinPath", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); var ddNameFunc = installerType.GetMethod("GetDreamDaemonName", BindingFlags.Instance | BindingFlags.NonPublic); var supportsCli = false; - var argArray = new object[] { byondVersion.Version, supportsCli }; + var argArray = new object[] { engineVersion.Version, supportsCli }; // https://stackoverflow.com/questions/2438065/how-can-i-invoke-a-method-with-an-out-parameter var ddPath = ioManager.ConcatPath( @@ -463,7 +463,7 @@ static async Task TestMapThreadsVersion( Assert.IsTrue((bool)argArray[1]); - var shouldSupportMapThreads = byondVersion.Version >= MapThreadsVersion(); + var shouldSupportMapThreads = engineVersion.Version >= MapThreadsVersion(); await File.WriteAllBytesAsync("fake.dmb", Array.Empty(), CancellationToken.None); From a4a3b78645a9b53fc311ff95cf03d9afb2813723 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 01:50:39 -0400 Subject: [PATCH 073/717] Clean up ByondResponse --- .../Models/Response/ByondResponse.cs | 6 +++--- .../Controllers/ByondController.cs | 6 +++--- .../TestApiClient.cs | 10 +++++----- .../Live/Instance/ByondTest.cs | 14 +++++++------- .../Live/Instance/InstanceTest.cs | 4 ++-- .../Live/Instance/WatchdogTest.cs | 16 ++++++++-------- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs b/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs index e289de30a25..aff07a3954d 100644 --- a/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs @@ -3,13 +3,13 @@ namespace Tgstation.Server.Api.Models.Response { /// - /// Represents an installed . + /// Represents an installed . /// public sealed class ByondResponse { /// - /// The represented . + /// The represented . If that indicates none were found. /// - public EngineVersion? Version { get; set; } + public EngineVersion? EngineVersion { get; set; } } } diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index c5857f54877..33b9d55ee1b 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -98,7 +98,7 @@ public ValueTask Read() Json( new ByondResponse { - Version = instance.EngineManager.ActiveVersion, + EngineVersion = instance.EngineManager.ActiveVersion, }))); /// @@ -122,10 +122,10 @@ public ValueTask List([FromQuery] int? page, [FromQuery] int? pag .InstalledVersions .Select(x => new ByondResponse { - Version = x, + EngineVersion = x, }) .AsQueryable() - .OrderBy(x => x.Version))), + .OrderBy(x => x.EngineVersion))), null, page, pageSize, diff --git a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs index 0edc228b18e..e0156fc0f46 100644 --- a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs +++ b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs @@ -26,7 +26,7 @@ public async Task TestDeserializingByondModelsWork() { var sample = new ByondResponse { - Version = new EngineVersion + EngineVersion = new EngineVersion { Engine = EngineType.Byond, Version = new Version(511, 1385) @@ -50,9 +50,9 @@ public async Task TestDeserializingByondModelsWork() var client = new ApiClient(httpClient.Object, new Uri("http://fake.com"), new ApiHeaders(new ProductHeaderValue("fake"), "fake"), null, false); var result = await client.Read(Routes.Byond, default); - Assert.AreEqual(sample.Version, result.Version); - Assert.AreEqual(0, result.Version.Version.Build); // sucks but we can't do better really - Assert.IsFalse(result.Version.CustomIteration.HasValue); + Assert.AreEqual(sample.EngineVersion, result.EngineVersion); + Assert.AreEqual(0, result.EngineVersion.Version.Build); // sucks but we can't do better really + Assert.IsFalse(result.EngineVersion.CustomIteration.HasValue); } [TestMethod] @@ -60,7 +60,7 @@ public async Task TestUnrecognizedResponse() { var sample = new ByondResponse { - Version = new EngineVersion + EngineVersion = new EngineVersion { Engine = EngineType.Byond, Version = new Version(511, 1385) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index a6525a8d923..77135b84c4c 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -182,8 +182,8 @@ async Task TestDeletes(CancellationToken cancellationToken) var newVersions = await byondClient.InstalledVersions(null, cancellationToken); Assert.IsNotNull(newVersions); Assert.AreEqual(1, newVersions.Count); - Assert.AreEqual(testVersion.Version.Semver(), newVersions[0].Version.Version.Semver()); - Assert.AreEqual(1, newVersions[0].Version.CustomIteration); + Assert.AreEqual(testVersion.Version.Semver(), newVersions[0].EngineVersion.Version.Semver()); + Assert.AreEqual(1, newVersions[0].EngineVersion.CustomIteration); } async Task TestInstallFakeVersion(CancellationToken cancellationToken) @@ -214,8 +214,8 @@ async Task TestInstallStable(CancellationToken cancellationToken) Assert.IsNotNull(test.InstallJob); await WaitForJob(test.InstallJob, 180, false, null, cancellationToken); var currentShit = await byondClient.ActiveVersion(cancellationToken); - Assert.AreEqual(newModel, currentShit.Version); - Assert.IsFalse(currentShit.Version.CustomIteration.HasValue); + Assert.AreEqual(newModel, currentShit.EngineVersion); + Assert.IsFalse(currentShit.EngineVersion.CustomIteration.HasValue); var dreamMaker = "DreamMaker"; if (new PlatformIdentifier().IsWindows) @@ -235,7 +235,7 @@ async Task TestNoVersion(CancellationToken cancellationToken) var allVersionsTask = byondClient.InstalledVersions(null, cancellationToken); var currentShit = await byondClient.ActiveVersion(cancellationToken); Assert.IsNotNull(currentShit); - Assert.IsNull(currentShit.Version); + Assert.IsNull(currentShit.EngineVersion); var otherShit = await allVersionsTask; Assert.IsNotNull(otherShit); Assert.AreEqual(0, otherShit.Count); @@ -299,8 +299,8 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) await WaitForJob(test2.InstallJob, 30, false, null, cancellationToken); var newSettings = await byondClient.ActiveVersion(cancellationToken); - Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 0), newSettings.Version.Version); - Assert.AreEqual(2, newSettings.Version.CustomIteration); + Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 0), newSettings.EngineVersion.Version); + Assert.AreEqual(2, newSettings.EngineVersion.CustomIteration); // test a few switches var installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index d7d1e79b087..69435c0674a 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -206,8 +206,8 @@ await Task.WhenAll( Assert.IsNotNull(compatVersion.SourceSHA); Assert.AreNotEqual(Limits.MaximumCommitShaLength, compatVersion.SourceSHA.Length); var activeVersion = await instanceClient.Byond.ActiveVersion(cancellationToken); - Assert.AreEqual(Limits.MaximumCommitShaLength, activeVersion.Version.SourceSHA.Length); - Assert.AreEqual(compatVersion, activeVersion.Version); + Assert.AreEqual(Limits.MaximumCommitShaLength, activeVersion.EngineVersion.SourceSHA.Length); + Assert.AreEqual(compatVersion, activeVersion.EngineVersion); } var configSetupTask = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata).SetupDMApiTests(cancellationToken); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 2224e635205..7f96f041c5c 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -94,17 +94,17 @@ async Task CheckByondVersions() Assert.AreEqual(1, list.Count); var byondVersion = list[0]; - Assert.AreEqual(1, byondVersion.Version.CustomIteration); - Assert.AreEqual(testVersion.Engine, byondVersion.Version.Engine); + Assert.AreEqual(1, byondVersion.EngineVersion.CustomIteration); + Assert.AreEqual(testVersion.Engine, byondVersion.EngineVersion.Engine); if (testVersion.Version != null) { - Assert.AreEqual(testVersion.Version.Major, byondVersion.Version.Version.Major); - Assert.AreEqual(testVersion.Version.Minor, byondVersion.Version.Version.Minor); + Assert.AreEqual(testVersion.Version.Major, byondVersion.EngineVersion.Version.Major); + Assert.AreEqual(testVersion.Version.Minor, byondVersion.EngineVersion.Version.Minor); } else { - Assert.IsNull(byondVersion.Version.Version); - Assert.AreEqual(testVersion.SourceSHA, byondVersion.Version.SourceSHA); + Assert.IsNull(byondVersion.EngineVersion.Version); + Assert.AreEqual(testVersion.SourceSHA, byondVersion.EngineVersion.SourceSHA); } } @@ -244,7 +244,7 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo var testCustomRevision = 1; var currentByond = await instanceClient.Byond.ActiveVersion(cancellationToken); Assert.IsNotNull(currentByond); - Assert.AreEqual(testVersion, currentByond.Version); + Assert.AreEqual(testVersion, currentByond.EngineVersion); // Change the active version and check we get delayed while deleting the old one because the watchdog is using it var setActiveResponse = await instanceClient.Byond.SetActiveVersion( @@ -976,7 +976,7 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken var versionToInstall = testVersion; var currentByondVersion = await instanceClient.Byond.ActiveVersion(cancellationToken); - Assert.AreNotEqual(versionToInstall, currentByondVersion.Version); + Assert.AreNotEqual(versionToInstall, currentByondVersion.EngineVersion); var initialStatus = await instanceClient.DreamDaemon.Read(cancellationToken); From 32873fa618ab2a2e6af4128597e5352503ec47c0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 10:58:16 -0400 Subject: [PATCH 074/717] More API sanity for `EngineVersion`s --- .../Request/ByondVersionDeleteRequest.cs | 12 +- .../Models/Request/ByondVersionRequest.cs | 9 +- .../Controllers/ByondController.cs | 32 ++--- .../TestApiClient.cs | 2 +- .../Live/Instance/ByondTest.cs | 111 ++++++++++++------ .../Live/Instance/InstanceTest.cs | 9 +- .../Live/Instance/WatchdogTest.cs | 54 ++++++--- .../Program.cs | 5 +- 8 files changed, 151 insertions(+), 83 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs b/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs index 3a81b191ccf..692c270a5e7 100644 --- a/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs @@ -1,13 +1,15 @@ -using System; - -using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Api.Models.Internal; namespace Tgstation.Server.Api.Models.Request { /// - /// A request to delete a specific . + /// A request to delete a specific . /// - public class ByondVersionDeleteRequest : EngineVersion + public class ByondVersionDeleteRequest { + /// + /// The to delete. + /// + public EngineVersion? EngineVersion { get; set; } } } diff --git a/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs b/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs index c56edecfd66..de00f22994c 100644 --- a/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs @@ -3,10 +3,15 @@ namespace Tgstation.Server.Api.Models.Request { /// - /// A request to install a . + /// A request to switch to a given . /// - public sealed class ByondVersionRequest : EngineVersion + public sealed class ByondVersionRequest { + /// + /// The to switch to. + /// + public EngineVersion? EngineVersion { get; set; } + /// /// If a custom BYOND version is to be uploaded. /// diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index 33b9d55ee1b..22dcc4f2c1f 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -153,7 +153,8 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode #pragma warning restore CA1506 #pragma warning restore CA1502 { - var earlyOut = ValidateByondVersion(model); + ArgumentNullException.ThrowIfNull(model); + var earlyOut = ValidateEngineVersion(model.EngineVersion); if (earlyOut != null) return earlyOut; @@ -170,7 +171,7 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode async instance => { var byondManager = instance.EngineManager; - var versionAlreadyInstalled = !uploadingZip && byondManager.InstalledVersions.Any(x => x.Equals(model)); + var versionAlreadyInstalled = !uploadingZip && byondManager.InstalledVersions.Any(x => x.Equals(model.EngineVersion)); if (versionAlreadyInstalled) { Logger.LogInformation( @@ -181,7 +182,7 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode try { - await byondManager.ChangeVersion(null, model, null, false, cancellationToken); + await byondManager.ChangeVersion(null, model.EngineVersion, null, false, cancellationToken); } catch (InvalidOperationException ex) { @@ -195,7 +196,7 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode if (!versionAlreadyInstalled) { - if (model.CustomIteration.HasValue) + if (model.EngineVersion.CustomIteration.HasValue) return BadRequest(new ErrorMessageResponse(ErrorCode.EngineNonExistentCustomVersion)); Logger.LogInformation( @@ -207,7 +208,7 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode // run the install through the job manager var job = new Models.Job { - Description = $"Install {(!uploadingZip ? String.Empty : "custom ")}{model.Engine.Value} version {model.Version}", + Description = $"Install {(!uploadingZip ? String.Empty : "custom ")}{model.EngineVersion.Engine.Value} version {model.EngineVersion.Version}", StartedBy = AuthenticationContext.User, CancelRightsType = RightsType.Byond, CancelRight = (ulong)ByondRights.CancelInstall, @@ -244,7 +245,7 @@ await jobManager.RegisterOperation( await using (zipFileStream) await core.EngineManager.ChangeVersion( progressHandler, - model, + model.EngineVersion, zipFileStream, true, jobCancellationToken); @@ -283,7 +284,8 @@ await core.EngineManager.ChangeVersion( [ProducesResponseType(typeof(ErrorMessageResponse), 410)] public async ValueTask Delete([FromBody] ByondVersionDeleteRequest model, CancellationToken cancellationToken) { - var earlyOut = ValidateByondVersion(model); + ArgumentNullException.ThrowIfNull(model); + var earlyOut = ValidateEngineVersion(model.EngineVersion); if (earlyOut != null) return earlyOut; @@ -292,11 +294,11 @@ public async ValueTask Delete([FromBody] ByondVersionDeleteReques { var byondManager = instance.EngineManager; - if (model.Equals(byondManager.ActiveVersion)) + if (model.EngineVersion.Equals(byondManager.ActiveVersion)) return ValueTask.FromResult( Conflict(new ErrorMessageResponse(ErrorCode.EngineCannotDeleteActiveVersion))); - var versionNotInstalled = !byondManager.InstalledVersions.Any(x => x.Equals(model)); + var versionNotInstalled = !byondManager.InstalledVersions.Any(x => x.Equals(model.EngineVersion)); return ValueTask.FromResult( versionNotInstalled @@ -307,7 +309,7 @@ public async ValueTask Delete([FromBody] ByondVersionDeleteReques if (notInstalledResponse != null) return notInstalledResponse; - var isByondVersion = model.Engine.Value == EngineType.Byond; + var isByondVersion = model.EngineVersion.Engine.Value == EngineType.Byond; // run the install through the job manager var job = new Models.Job @@ -317,7 +319,7 @@ public async ValueTask Delete([FromBody] ByondVersionDeleteReques CancelRightsType = RightsType.Byond, CancelRight = (ulong)( isByondVersion - ? model.Version.Build != -1 + ? model.EngineVersion.Version.Build != -1 ? ByondRights.InstallOfficialOrChangeActiveByondVersion : ByondRights.InstallCustomByondVersion : ByondRights.InstallCustomOpenDreamVersion | ByondRights.InstallOfficialOrChangeActiveOpenDreamVersion), @@ -327,7 +329,7 @@ public async ValueTask Delete([FromBody] ByondVersionDeleteReques await jobManager.RegisterOperation( job, (instanceCore, databaseContextFactory, job, progressReporter, jobCancellationToken) - => instanceCore.EngineManager.DeleteVersion(progressReporter, model, jobCancellationToken), + => instanceCore.EngineManager.DeleteVersion(progressReporter, model.EngineVersion, jobCancellationToken), cancellationToken); var apiResponse = job.ToApi(); @@ -339,11 +341,9 @@ await jobManager.RegisterOperation( /// /// The to validate and normalize. /// The to return, if any. - BadRequestObjectResult ValidateByondVersion(EngineVersion version) + BadRequestObjectResult ValidateEngineVersion(EngineVersion version) { - ArgumentNullException.ThrowIfNull(version); - - if (!version.Engine.HasValue) + if (version == null || !version.Engine.HasValue) return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); var isByond = version.Engine.Value == EngineType.Byond; diff --git a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs index e0156fc0f46..941d254133f 100644 --- a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs +++ b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs @@ -51,7 +51,7 @@ public async Task TestDeserializingByondModelsWork() var result = await client.Read(Routes.Byond, default); Assert.AreEqual(sample.EngineVersion, result.EngineVersion); - Assert.AreEqual(0, result.EngineVersion.Version.Build); // sucks but we can't do better really + Assert.AreEqual(-1, result.EngineVersion.Version.Build); Assert.IsFalse(result.EngineVersion.CustomIteration.HasValue); } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index 77135b84c4c..0779707fd76 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -114,7 +114,10 @@ ValueTask TestInstallNullVersion(CancellationToken cancellationToken) () => byondClient.SetActiveVersion( new ByondVersionRequest { - Engine = testEngine, + EngineVersion = new EngineVersion + { + Engine = testEngine, + } }, null, cancellationToken), @@ -132,36 +135,48 @@ async Task TestDeletes(CancellationToken cancellationToken) { var deleteThisOneBecauseItWasntPartOfTheOriginalTest = await byondClient.DeleteVersion(new ByondVersionDeleteRequest { - Engine = testEngine, - Version = testVersion.Version, - CustomIteration = 2, + EngineVersion = new EngineVersion + { + Engine = testEngine, + Version = testVersion.Version, + CustomIteration = 2, + } }, cancellationToken); await WaitForJob(deleteThisOneBecauseItWasntPartOfTheOriginalTest, 30, false, null, cancellationToken); var nonExistentUninstallResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( new ByondVersionDeleteRequest { - Version = new(509, 1000), - Engine = testEngine, + EngineVersion = new EngineVersion + { + Version = new(509, 1000), + Engine = testEngine, + } }, cancellationToken), ErrorCode.ResourceNotPresent); var uninstallResponseTask = byondClient.DeleteVersion( new ByondVersionDeleteRequest { - Version = testVersion.Version, - Engine = testVersion.Engine, - SourceSHA = testVersion.SourceSHA, + EngineVersion = new EngineVersion + { + Version = testVersion.Version, + Engine = testVersion.Engine, + SourceSHA = testVersion.SourceSHA, + } }, cancellationToken); var badBecauseActiveResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( new ByondVersionDeleteRequest { - Version = testVersion.Version, - Engine = testVersion.Engine, - SourceSHA = testVersion.SourceSHA, - CustomIteration = 1, + EngineVersion = new EngineVersion + { + Version = testVersion.Version, + Engine = testVersion.Engine, + SourceSHA = testVersion.SourceSHA, + CustomIteration = 1, + } }, cancellationToken), ErrorCode.EngineCannotDeleteActiveVersion); @@ -190,12 +205,15 @@ async Task TestInstallFakeVersion(CancellationToken cancellationToken) { var newModel = new ByondVersionRequest { - Version = new Version(5011, 1385) + EngineVersion = new EngineVersion + { + Version = new Version(5011, 1385), + } }; await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(newModel, null, cancellationToken), ErrorCode.ModelValidationFailure); - newModel.Engine = testEngine; + newModel.EngineVersion.Engine = testEngine; var test = await byondClient.SetActiveVersion(newModel, null, cancellationToken); Assert.IsNotNull(test.InstallJob); @@ -206,22 +224,25 @@ async Task TestInstallStable(CancellationToken cancellationToken) { var newModel = new ByondVersionRequest { - Version = testVersion.Version, - Engine = testVersion.Engine, - SourceSHA = testVersion.SourceSHA, + EngineVersion = new EngineVersion + { + Version = testVersion.Version, + Engine = testVersion.Engine, + SourceSHA = testVersion.SourceSHA, + } }; var test = await byondClient.SetActiveVersion(newModel, null, cancellationToken); Assert.IsNotNull(test.InstallJob); await WaitForJob(test.InstallJob, 180, false, null, cancellationToken); var currentShit = await byondClient.ActiveVersion(cancellationToken); - Assert.AreEqual(newModel, currentShit.EngineVersion); + Assert.AreEqual(newModel.EngineVersion, currentShit.EngineVersion); Assert.IsFalse(currentShit.EngineVersion.CustomIteration.HasValue); var dreamMaker = "DreamMaker"; if (new PlatformIdentifier().IsWindows) dreamMaker += ".exe"; - var dreamMakerDir = Path.Combine(metadata.Path, "Byond", newModel.Version.ToString(), "byond", "bin"); + var dreamMakerDir = Path.Combine(metadata.Path, "Byond", newModel.EngineVersion.Version.ToString(), "byond", "bin"); Assert.IsTrue(Directory.Exists(dreamMakerDir), $"Directory {dreamMakerDir} does not exist!"); Assert.IsTrue( @@ -271,10 +292,13 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) var test = await byondClient.SetActiveVersion( new ByondVersionRequest { - Engine = testVersion.Engine, - Version = testVersion.Version, - SourceSHA = testVersion.SourceSHA, - UploadCustomZip = true + EngineVersion = new EngineVersion + { + Engine = testVersion.Engine, + Version = testVersion.Version, + SourceSHA = testVersion.SourceSHA, + }, + UploadCustomZip = true, }, stableBytesMs, cancellationToken); @@ -287,10 +311,14 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) var test2 = await byondClient.SetActiveVersion( new ByondVersionRequest { - Version = testVersion.Version, - SourceSHA = testVersion.SourceSHA, - Engine = testVersion.Engine, - UploadCustomZip = true + EngineVersion = new EngineVersion + { + Version = testVersion.Version, + SourceSHA = testVersion.SourceSHA, + Engine = testVersion.Engine, + }, + UploadCustomZip = true, + }, stableBytesMs, cancellationToken); @@ -305,23 +333,32 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) // test a few switches var installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest { - Version = testVersion.Version, - SourceSHA = testVersion.SourceSHA, - Engine = testVersion.Engine, + EngineVersion = new EngineVersion + { + Version = testVersion.Version, + SourceSHA = testVersion.SourceSHA, + Engine = testVersion.Engine, + } }, null, cancellationToken); Assert.IsNull(installResponse.InstallJob); await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(new ByondVersionRequest { - Version = testVersion.Version, - Engine = testEngine, - CustomIteration = 3, + EngineVersion = new EngineVersion + { + Version = testVersion.Version, + Engine = testEngine, + CustomIteration = 3, + } }, null, cancellationToken), ErrorCode.EngineNonExistentCustomVersion); installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest { - Version = new Version(testVersion.Version.Major, testVersion.Version.Minor), - Engine = testEngine, - CustomIteration = 1, + EngineVersion = new EngineVersion + { + Version = new Version(testVersion.Version.Major, testVersion.Version.Minor), + Engine = testEngine, + CustomIteration = 1, + } }, null, cancellationToken); Assert.IsNull(installResponse.InstallJob); } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 69435c0674a..96b8b86492e 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -182,9 +182,12 @@ public async Task RunCompatTests( installJob2 = await instanceClient.Byond.SetActiveVersion(new ByondVersionRequest { UploadCustomZip = true, - Version = compatVersion.Version, - Engine = compatVersion.Engine, - SourceSHA = compatVersion.SourceSHA + EngineVersion = new EngineVersion + { + Version = compatVersion.Version, + Engine = compatVersion.Engine, + SourceSHA = compatVersion.SourceSHA, + }, }, stableBytesMs, cancellationToken); } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 7f96f041c5c..7ba10fdaa72 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -250,9 +250,12 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo var setActiveResponse = await instanceClient.Byond.SetActiveVersion( new ByondVersionRequest { - Version = testCustomVersion, - Engine = testVersion.Engine, - CustomIteration = testCustomRevision, + EngineVersion = new EngineVersion + { + Version = testCustomVersion, + Engine = testVersion.Engine, + CustomIteration = testCustomRevision, + } }, null, cancellationToken); @@ -263,9 +266,12 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo var deleteJob = await instanceClient.Byond.DeleteVersion( new ByondVersionDeleteRequest { - Version = testVersion.Version, - SourceSHA = testVersion.SourceSHA, - Engine = testVersion.Engine, + EngineVersion = new EngineVersion + { + Version = testVersion.Version, + SourceSHA = testVersion.SourceSHA, + Engine = testVersion.Engine, + } }, cancellationToken); @@ -280,9 +286,12 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo setActiveResponse = await instanceClient.Byond.SetActiveVersion( new ByondVersionRequest { - Version = testVersion.Version, - Engine = testVersion.Engine, - SourceSHA = testVersion.SourceSHA + EngineVersion = new EngineVersion + { + Version = testVersion.Version, + Engine = testVersion.Engine, + SourceSHA = testVersion.SourceSHA + } }, null, cancellationToken); @@ -297,9 +306,12 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo setActiveResponse = await instanceClient.Byond.SetActiveVersion( new ByondVersionRequest { - Version = testCustomVersion, - Engine = testVersion.Engine, - CustomIteration = testCustomRevision, + EngineVersion = new EngineVersion + { + Version = testCustomVersion, + Engine = testVersion.Engine, + CustomIteration = testCustomRevision, + } }, null, cancellationToken); @@ -310,9 +322,12 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo deleteJob = await instanceClient.Byond.DeleteVersion( new ByondVersionDeleteRequest { - Version = testVersion.Version, - Engine = testVersion.Engine, - SourceSHA = testVersion.SourceSHA, + EngineVersion = new EngineVersion + { + Version = testVersion.Version, + Engine = testVersion.Engine, + SourceSHA = testVersion.SourceSHA, + } }, cancellationToken); @@ -989,9 +1004,12 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken var byondInstallJobTask = instanceClient.Byond.SetActiveVersion( new ByondVersionRequest { - Version = versionToInstall.Version, - Engine = versionToInstall.Engine, - SourceSHA = versionToInstall.SourceSHA, + EngineVersion = new EngineVersion + { + Version = versionToInstall.Version, + Engine = versionToInstall.Engine, + SourceSHA = versionToInstall.SourceSHA, + } }, null, cancellationToken); diff --git a/tools/Tgstation.Server.Migrator.Comms/Program.cs b/tools/Tgstation.Server.Migrator.Comms/Program.cs index 754d9e69d58..91ad70de97c 100644 --- a/tools/Tgstation.Server.Migrator.Comms/Program.cs +++ b/tools/Tgstation.Server.Migrator.Comms/Program.cs @@ -230,7 +230,10 @@ static async Task Migrate(IClient tgs3Client, ushort apiPort) Console.WriteLine($"Found installed BYOND version: {byondVersion.Major}.{byondVersion.Minor}"); byondVersionRequest = new ByondVersionRequest { - Version = byondVersion + EngineVersion = new EngineVersion + { + Version = byondVersion + } }; } From cba40d8e2c2e3ac2ee502a8f04d60e590a9263f6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 10:59:48 -0400 Subject: [PATCH 075/717] Make .dme modification use saner line endings --- src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index 8b69627cf76..3b929318107 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -942,7 +942,7 @@ async ValueTask ModifyDme(Models.CompileJob job, CancellationToken cancellationT } } - dmeBytes = Encoding.UTF8.GetBytes(String.Join(Environment.NewLine, dmeLines)); + dmeBytes = Encoding.UTF8.GetBytes(String.Join('\n', dmeLines)); await ioManager.WriteAllBytes(dmePath, dmeBytes, cancellationToken); } From 9081ad4736ba00c7298f90b21623f4611709dccc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 14:03:20 -0400 Subject: [PATCH 076/717] Additional failure state for Bridge requests --- src/DMAPI/tgs/v5/bridge.dm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/DMAPI/tgs/v5/bridge.dm b/src/DMAPI/tgs/v5/bridge.dm index 37f58bcdf63..cc12c1ddc8f 100644 --- a/src/DMAPI/tgs/v5/bridge.dm +++ b/src/DMAPI/tgs/v5/bridge.dm @@ -81,11 +81,16 @@ TGS_ERROR_LOG("Failed bridge request: [bridge_request]") return - var/response_json = file2text(export_response["CONTENT"]) - if(!response_json) + var/content = export_response["CONTENT"] + if(!content) TGS_ERROR_LOG("Failed bridge request, missing content!") return + var/response_json = file2text(content) + if(!response_json) + TGS_ERROR_LOG("Failed bridge request, failed to load content!") + return + var/list/bridge_response = json_decode(response_json) if(!bridge_response) TGS_ERROR_LOG("Failed bridge request, bad json: [response_json]") From eb516744fb7be88d247806d7e605103ca40f6c4a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 15:38:31 -0400 Subject: [PATCH 077/717] Fix engine version parsing --- .../Models/Internal/EngineVersion.cs | 2 +- .../Models/TestEngineVersion.cs | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/Tgstation.Server.Api.Tests/Models/TestEngineVersion.cs diff --git a/src/Tgstation.Server.Api/Models/Internal/EngineVersion.cs b/src/Tgstation.Server.Api/Models/Internal/EngineVersion.cs index 65a348b20fb..2f3279e93bb 100644 --- a/src/Tgstation.Server.Api/Models/Internal/EngineVersion.cs +++ b/src/Tgstation.Server.Api/Models/Internal/EngineVersion.cs @@ -51,7 +51,7 @@ public static bool TryParse(string input, out EngineVersion? engineVersion) var splits = input.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries); engineVersion = null; - if (splits.Length > 2) + if (splits.Length > 3) return false; EngineType engine; diff --git a/tests/Tgstation.Server.Api.Tests/Models/TestEngineVersion.cs b/tests/Tgstation.Server.Api.Tests/Models/TestEngineVersion.cs new file mode 100644 index 00000000000..eb7a58e62d9 --- /dev/null +++ b/tests/Tgstation.Server.Api.Tests/Models/TestEngineVersion.cs @@ -0,0 +1,40 @@ +using System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Tgstation.Server.Api.Models.Internal; + +namespace Tgstation.Server.Api.Models.Tests +{ + [TestClass] + public sealed class TestEngineVersion + { + [TestMethod] + public void TestParsing() + { + Assert.IsTrue(EngineVersion.TryParse("OpenDream-6894ba0702c1764d333eb52aa0cc211d62e2cb1c-1", out var version)); + Assert.AreEqual(EngineType.OpenDream, version.Engine); + Assert.AreEqual("6894ba0702c1764d333eb52aa0cc211d62e2cb1c", version.SourceSHA); + Assert.IsNull(version.Version); + Assert.AreEqual(1, version.CustomIteration); + + Assert.IsTrue(EngineVersion.TryParse("OpenDream-6894ba0702c1764d333eb52aa0cc211d62e2cb1c", out version)); + Assert.AreEqual(EngineType.OpenDream, version.Engine); + Assert.AreEqual("6894ba0702c1764d333eb52aa0cc211d62e2cb1c", version.SourceSHA); + Assert.IsNull(version.Version); + Assert.IsFalse(version.CustomIteration.HasValue); + + Assert.IsTrue(EngineVersion.TryParse("515.1616", out version)); + Assert.AreEqual(EngineType.Byond, version.Engine); + Assert.AreEqual(new Version(515, 1616), version.Version); + Assert.IsNull(version.SourceSHA); + Assert.IsFalse(version.CustomIteration.HasValue); + + Assert.IsTrue(EngineVersion.TryParse("515.1616.12", out version)); + Assert.AreEqual(EngineType.Byond, version.Engine); + Assert.AreEqual(new Version(515, 1616), version.Version); + Assert.IsNull(version.SourceSHA); + Assert.AreEqual(12, version.CustomIteration); + } + } +} From a1f1dbc58bf7bc36544758272d8b41f227daad12 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 15:38:47 -0400 Subject: [PATCH 078/717] Make a log message correct --- src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs index c2570119d53..ac2acba24da 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs @@ -247,7 +247,7 @@ await databaseContextFactory.UseContext( if (!Api.Models.Internal.EngineVersion.TryParse(compileJob.ByondVersion, out var engineVersion)) { - logger.LogWarning("Error loading compile job, bad BYOND version: {0}", compileJob.ByondVersion); + logger.LogWarning("Error loading compile job, bad engine version: {0}", compileJob.ByondVersion); return null; // omae wa mou shinderu } From 0fefec9f57ecdd68fa9bac5c0c293908ae2b6e92 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 15:39:36 -0400 Subject: [PATCH 079/717] Fix OpenDream engine parameter encoding --- .../Components/Engine/ByondInstallation.cs | 25 ++++---- .../Engine/EngineInstallationBase.cs | 57 +++++++++++++++++++ .../Engine/OpenDreamInstallation.cs | 46 ++++++--------- 3 files changed, 83 insertions(+), 45 deletions(-) create mode 100644 src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs index 780fc91a5ab..345ee5e743b 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Threading.Tasks; -using System.Web; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; @@ -14,25 +12,25 @@ namespace Tgstation.Server.Host.Components.Engine /// /// Implementation of for . /// - sealed class ByondInstallation : IEngineInstallation + sealed class ByondInstallation : EngineInstallationBase { /// - public EngineVersion Version { get; } + public override EngineVersion Version { get; } /// - public string ServerExePath { get; } + public override string ServerExePath { get; } /// - public string CompilerExePath { get; } + public override string CompilerExePath { get; } /// - public bool PromptsForNetworkAccess { get; } + public override bool PromptsForNetworkAccess { get; } /// - public bool HasStandardOutput { get; } + public override bool HasStandardOutput { get; } /// - public Task InstallationTask { get; } + public override Task InstallationTask { get; } /// /// If map threads are supported by the . @@ -103,7 +101,7 @@ public ByondInstallation( } /// - public string FormatServerArguments( + public override string FormatServerArguments( IDmbProvider dmbProvider, IReadOnlyDictionary parameters, DreamDaemonLaunchParameters launchParameters, @@ -113,10 +111,7 @@ public string FormatServerArguments( ArgumentNullException.ThrowIfNull(parameters); ArgumentNullException.ThrowIfNull(launchParameters); - var parametersString = String.Join('&', parameters.Select(kvp => $"{HttpUtility.UrlEncode(kvp.Key)}={HttpUtility.UrlEncode(kvp.Value)}")); - - if (!String.IsNullOrEmpty(launchParameters.AdditionalParameters)) - parametersString = $"{parametersString}&{launchParameters.AdditionalParameters}"; + var parametersString = EncodeParameters(parameters, launchParameters); var arguments = String.Format( CultureInfo.InvariantCulture, @@ -142,7 +137,7 @@ public string FormatServerArguments( } /// - public string FormatCompilerArguments(string dmePath) + public override string FormatCompilerArguments(string dmePath) => $"-clean \"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\""; } } diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs new file mode 100644 index 00000000000..8bd53be358d --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Web; + +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Components.Deployment; + +namespace Tgstation.Server.Host.Components.Engine +{ + /// + abstract class EngineInstallationBase : IEngineInstallation + { + /// + public abstract EngineVersion Version { get; } + + /// + public abstract string ServerExePath { get; } + + /// + public abstract string CompilerExePath { get; } + + /// + public abstract bool HasStandardOutput { get; } + + /// + public abstract bool PromptsForNetworkAccess { get; } + + /// + public abstract Task InstallationTask { get; } + + /// + /// Encode given parameters for passing as world.params on the command line. + /// + /// of parameters to encode. + /// The active . + /// The formatted parameters . + protected static string EncodeParameters( + IReadOnlyDictionary parameters, + DreamDaemonLaunchParameters launchParameters) + { + var parametersString = String.Join('&', parameters.Select(kvp => $"{HttpUtility.UrlEncode(kvp.Key)}={HttpUtility.UrlEncode(kvp.Value)}")); + + if (!String.IsNullOrEmpty(launchParameters.AdditionalParameters)) + parametersString = $"{parametersString}&{launchParameters.AdditionalParameters}"; + + return parametersString; + } + + /// + public abstract string FormatCompilerArguments(string dmePath); + + /// + public abstract string FormatServerArguments(IDmbProvider dmbProvider, IReadOnlyDictionary parameters, DreamDaemonLaunchParameters launchParameters, string logFilePath); + } +} diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index 66a2e11b9dd..e6413570f16 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; -using System.Web; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; @@ -13,25 +11,25 @@ namespace Tgstation.Server.Host.Components.Engine /// /// Implementation of for . /// - sealed class OpenDreamInstallation : IEngineInstallation + sealed class OpenDreamInstallation : EngineInstallationBase { /// - public EngineVersion Version { get; } + public override EngineVersion Version { get; } /// - public string ServerExePath { get; } + public override string ServerExePath { get; } /// - public string CompilerExePath { get; } + public override string CompilerExePath { get; } /// - public bool PromptsForNetworkAccess => false; + public override bool PromptsForNetworkAccess => false; /// - public bool HasStandardOutput => true; + public override bool HasStandardOutput => true; /// - public Task InstallationTask { get; } + public override Task InstallationTask { get; } /// /// Initializes a new instance of the class. @@ -56,39 +54,27 @@ public OpenDreamInstallation( } /// - public string FormatServerArguments(IDmbProvider dmbProvider, IReadOnlyDictionary parameters, DreamDaemonLaunchParameters launchParameters, string logFilePath) + public override string FormatServerArguments( + IDmbProvider dmbProvider, + IReadOnlyDictionary parameters, + DreamDaemonLaunchParameters launchParameters, + string logFilePath) { ArgumentNullException.ThrowIfNull(dmbProvider); ArgumentNullException.ThrowIfNull(parameters); ArgumentNullException.ThrowIfNull(launchParameters); - var parametersString = String.Join(';', parameters.Select(kvp => $"{kvp.Key}={kvp.Value}")); + if (logFilePath != null) + throw new NotSupportedException("OpenDream does not support logging to a file!"); - if (!String.IsNullOrEmpty(launchParameters.AdditionalParameters)) - { - // TGS and BYOND expect url encoded params, OD takes unencoded - var unencodedAdditionalParams = String.Join( - ';', - launchParameters - .AdditionalParameters - .Split('&') - .Select( - singleParam => String.Join( - '=', - singleParam - .Split('=') - .Select( - encodedParam => HttpUtility.UrlDecode(encodedParam))))); - - parametersString = $"{parametersString};{unencodedAdditionalParams}"; - } + var parametersString = EncodeParameters(parameters, launchParameters); var arguments = $"--cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" \"{dmbProvider.DmbName}\""; return arguments; } /// - public string FormatCompilerArguments(string dmePath) + public override string FormatCompilerArguments(string dmePath) => $"--suppress-unimplemented --notices-enabled \"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\""; } } From 0853fd36e2bb84d6d0daaec70c20193d3aafc9c9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 15:40:19 -0400 Subject: [PATCH 080/717] Rename BYOND bin const to be more specific --- .../Components/Engine/ByondInstallerBase.cs | 4 ++-- .../Components/Engine/PosixByondInstaller.cs | 2 +- .../Components/Engine/WindowsByondInstaller.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index c465feb1df1..c584d42331f 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -22,7 +22,7 @@ abstract class ByondInstallerBase : EngineInstallerBase /// /// The path to the BYOND bin folder. /// - protected const string BinPath = "byond/bin"; + protected const string ByondBinPath = "byond/bin"; /// /// The name of BYOND's cache directory. @@ -89,7 +89,7 @@ public override IEngineInstallation CreateInstallation(EngineVersion version, st { CheckVersionValidity(version); - var binPathForVersion = IOManager.ConcatPath(path, BinPath); + var binPathForVersion = IOManager.ConcatPath(path, ByondBinPath); var supportsMapThreads = version.Version >= MapThreadsVersion; return new ByondInstallation( diff --git a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs index e82b3f133dc..c4906308b5a 100644 --- a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs @@ -89,7 +89,7 @@ async ValueTask WriteAndMakeExecutable(string pathToScript, string script) postWriteHandler.HandleWrite(IOManager.ResolvePath(pathToScript)); } - var basePath = IOManager.ConcatPath(path, BinPath); + var basePath = IOManager.ConcatPath(path, ByondBinPath); var ddTask = WriteAndMakeExecutable( IOManager.ConcatPath(basePath, GetDreamDaemonName(version.Version, out _)), diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 3c5b44f0975..95950c06d64 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -235,7 +235,7 @@ async ValueTask AddDreamDaemonToFirewall(EngineVersion version, string path, Can var dreamDaemonPath = IOManager.ResolvePath( IOManager.ConcatPath( path, - BinPath, + ByondBinPath, dreamDaemonName)); int exitCode; From 1e70e2d053a48d6154078374c48fac2f07edf7b6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 15:41:02 -0400 Subject: [PATCH 081/717] Handle OpenDream tripping over `PortBindTest` --- .../Components/Session/SessionControllerFactory.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 1168a37e8a5..997e8b4e718 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -216,6 +216,8 @@ public async ValueTask LaunchNew( logger.LogTrace("Begin session launch..."); if (!launchParameters.Port.HasValue) throw new InvalidOperationException("Given port is null!"); + + PortBindTest(launchParameters.Port.Value); switch (dmbProvider.CompileJob.MinimumSecurityLevel) { case DreamDaemonSecurity.Ultrasafe: @@ -249,11 +251,11 @@ public async ValueTask LaunchNew( "Launching session with CompileJob {compileJobId}...", dmbProvider.CompileJob.Id); - PortBindTest(launchParameters.Port.Value); - // mad this isn't abstracted but whatever if (dmbProvider.EngineVersion.Engine.Value == EngineType.Byond) await CheckPagerIsNotRunning(); + else if (dmbProvider.EngineVersion.Engine.Value == EngineType.OpenDream) + await asyncDelayer.Delay(TimeSpan.FromMilliseconds(1), cancellationToken); // OpenDream is 2fuckingfast and can trip after we bind tested the port string outputFilePath = null; var preserveLogFile = true; From 88773528a9cc7ce4fa0749f3bd22c8261f9e7789 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 15:42:26 -0400 Subject: [PATCH 082/717] Make some live tests more generic for OpenDream --- .../Live/Instance/DeploymentTest.cs | 9 +++-- .../Live/Instance/InstanceTest.cs | 23 ++++++------- .../Live/Instance/WatchdogTest.cs | 13 ++++--- .../Live/TestLiveServer.cs | 34 +++++++++++++------ 4 files changed, 49 insertions(+), 30 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs index 3861634aa26..8b5fab58c91 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs @@ -23,6 +23,7 @@ sealed class DeploymentTest : JobsRequiredTest readonly ushort dmPort; readonly ushort ddPort; readonly bool lowPriorityDeployments; + readonly EngineType testEngine; Task vpTest; @@ -31,7 +32,8 @@ public DeploymentTest( IJobsClient jobsClient, ushort dmPort, ushort ddPort, - bool lowPriorityDeployments) : base(jobsClient) + bool lowPriorityDeployments, + EngineType testEngine) : base(jobsClient) { this.instanceClient = instanceClient ?? throw new ArgumentNullException(nameof(instanceClient)); dreamMakerClient = instanceClient.DreamMaker; @@ -39,6 +41,7 @@ public DeploymentTest( this.dmPort = dmPort; this.ddPort = ddPort; this.lowPriorityDeployments = lowPriorityDeployments; + this.testEngine = testEngine; } public async ValueTask RunPreRepoClone(CancellationToken cancellationToken) @@ -61,12 +64,12 @@ async ValueTask CheckDreamDaemonPriority(Task deploymentJobWaitTask, Cancellatio // this doesn't check dm's priority, but it really should while (!deploymentJobWaitTask.IsCompleted) { - var allProcesses = TestLiveServer.GetDDProcessesOnPort(dmPort); + var allProcesses = TestLiveServer.GetEngineServerProcessesOnPort(testEngine, dmPort); if (allProcesses.Count == 0) continue; if (allProcesses.Count > 1) - Assert.Fail("Multiple DreamDaemon-like processes running!"); + Assert.Fail("Multiple engine-like processes running!"); using var process = allProcesses[0]; diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 96b8b86492e..31048283e5c 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -42,11 +42,12 @@ public async Task RunTests( bool lowPrioDeployment, CancellationToken cancellationToken) { - var byondTest = new ByondTest(instanceClient.Byond, instanceClient.Jobs, fileDownloader, instanceClient.Metadata, EngineType.Byond); + var testVersion = await ByondTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); + var byondTest = new ByondTest(instanceClient.Byond, instanceClient.Jobs, fileDownloader, instanceClient.Metadata, testVersion.Engine.Value); var chatTest = new ChatTest(instanceClient.ChatBots, instanceManagerClient, instanceClient.Jobs, instanceClient.Metadata); var configTest = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata); var repoTest = new RepositoryTest(instanceClient.Repository, instanceClient.Jobs); - var dmTest = new DeploymentTest(instanceClient, instanceClient.Jobs, dmPort, ddPort, lowPrioDeployment); + var dmTest = new DeploymentTest(instanceClient, instanceClient.Jobs, dmPort, ddPort, lowPrioDeployment, testVersion.Engine.Value); var byondTask = byondTest.Run(cancellationToken, out var firstInstall); var chatTask = chatTest.RunPreWatchdog(cancellationToken); @@ -62,8 +63,8 @@ public async Task RunTests( await dmTask; await byondTask; - await new WatchdogTest( - await ByondTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken), instanceClient, instanceManager, serverPort, highPrioDD, ddPort).Run(cancellationToken); + await new WatchdogTest(testVersion, instanceClient, instanceManager, serverPort, highPrioDD, ddPort) + .Run(cancellationToken); } public async Task RunCompatTests( @@ -74,12 +75,6 @@ public async Task RunCompatTests( bool highPrioDD, CancellationToken cancellationToken) { - if (compatVersion.Engine.Value == EngineType.OpenDream) -#if DEBUG - return; -#else - Assert.Fail("OD Compat test not ready!"); -#endif System.Console.WriteLine($"COMPAT TEST START: {compatVersion}"); const string Origin = "https://github.com/Cyberboss/common_core"; var cloneRequest = instanceClient.Repository.Clone(new RepositoryCreateRequest @@ -207,10 +202,14 @@ await Task.WhenAll( if (compatVersion.Engine.Value == EngineType.OpenDream) { Assert.IsNotNull(compatVersion.SourceSHA); - Assert.AreNotEqual(Limits.MaximumCommitShaLength, compatVersion.SourceSHA.Length); var activeVersion = await instanceClient.Byond.ActiveVersion(cancellationToken); Assert.AreEqual(Limits.MaximumCommitShaLength, activeVersion.EngineVersion.SourceSHA.Length); - Assert.AreEqual(compatVersion, activeVersion.EngineVersion); + Assert.AreEqual(compatVersion.SourceSHA, activeVersion.EngineVersion.SourceSHA); + Assert.AreEqual(compatVersion.Version, activeVersion.EngineVersion.Version); + Assert.AreEqual(compatVersion.Engine, activeVersion.EngineVersion.Engine); + Assert.AreEqual(1, activeVersion.EngineVersion.CustomIteration); + + compatVersion = activeVersion.EngineVersion; } var configSetupTask = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata).SetupDMApiTests(cancellationToken); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 7ba10fdaa72..24394f4a8b7 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -535,7 +535,7 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke CheckDDPriority(); // lock on to DD and pause it so it can't health check - var ddProcs = TestLiveServer.GetDDProcessesOnPort(ddPort).Where(x => !x.HasExited).ToList(); + var ddProcs = TestLiveServer.GetEngineServerProcessesOnPort(testVersion.Engine.Value, ddPort).Where(x => !x.HasExited).ToList(); if (ddProcs.Count != 1) Assert.Fail($"Incorrect number of DD processes: {ddProcs.Count}"); @@ -882,7 +882,7 @@ static void CheckEmbedsTest(MessageContent embedsResponse, DateTimeOffset startT void CheckDDPriority() { - var allProcesses = TestLiveServer.GetDDProcessesOnPort(ddPort).Where(x => !x.HasExited).ToList(); + var allProcesses = TestLiveServer.GetEngineServerProcessesOnPort(testVersion.Engine.Value, ddPort).Where(x => !x.HasExited).ToList(); if (allProcesses.Count == 0) Assert.Fail("Expected DreamDaemon to be running here"); @@ -1093,7 +1093,7 @@ public async Task StartAndLeaveRunning(CancellationToken cancellationToken) bool KillDD(bool require) { - var ddProcs = TestLiveServer.GetDDProcessesOnPort(ddPort).Where(x => !x.HasExited).ToList(); + var ddProcs = TestLiveServer.GetEngineServerProcessesOnPort(testVersion.Engine.Value, ddPort).Where(x => !x.HasExited).ToList(); if (require && ddProcs.Count == 0 || ddProcs.Count > 1) Assert.Fail($"Incorrect number of DD processes: {ddProcs.Count}"); @@ -1167,7 +1167,12 @@ await instanceClient.DreamMaker.Update(new DreamMakerRequest var ddInfo = await instanceClient.DreamDaemon.Read(cancellationToken); if (requireApi) - Assert.IsNotNull((ddInfo.StagedCompileJob ?? ddInfo.ActiveCompileJob).DMApiVersion); + { + var targetJob = ddInfo.StagedCompileJob ?? ddInfo.ActiveCompileJob; + Assert.IsNotNull(targetJob); + Assert.IsNotNull(targetJob.DMApiVersion); + } + return ddInfo; } diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 6bf1ccf6c25..ac589da22f6 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -60,12 +60,23 @@ public sealed class TestLiveServer readonly ServerClientFactory clientFactory = new (new ProductHeaderValue(Assembly.GetExecutingAssembly().GetName().Name, Assembly.GetExecutingAssembly().GetName().Version.ToString())); - public static List GetDDProcessesOnPort(ushort? port) + public static List GetEngineServerProcessesOnPort(EngineType engineType, ushort? port) { var result = new List(); - result.AddRange(System.Diagnostics.Process.GetProcessesByName("DreamDaemon")); - if (new PlatformIdentifier().IsWindows) - result.AddRange(System.Diagnostics.Process.GetProcessesByName("dd")); + + switch (engineType) { + case EngineType.Byond: + result.AddRange(System.Diagnostics.Process.GetProcessesByName("DreamDaemon")); + if (new PlatformIdentifier().IsWindows) + result.AddRange(System.Diagnostics.Process.GetProcessesByName("dd")); + break; + case EngineType.OpenDream: + result.AddRange(System.Diagnostics.Process.GetProcessesByName("OpenDreamServer")); + break; + default: + Assert.Fail($"Unknown engine type: {engineType}"); + return null; + } if (port.HasValue) result = result.Where(x => @@ -102,11 +113,12 @@ private static string GetCommandLine(System.Diagnostics.Process process) } } - static void TerminateAllDDs() + static void TerminateAllEngineServers() { - foreach (var proc in GetDDProcessesOnPort(null)) - using (proc) - proc.Kill(); + foreach (var enumValue in Enum.GetValues()) + foreach (var proc in GetEngineServerProcessesOnPort(enumValue, null)) + using (proc) + proc.Kill(); } static ushort FreeTcpPort(params ushort[] usedPorts) @@ -1057,7 +1069,7 @@ async Task TestTgsInternal(CancellationToken hardCancellationToken) using var serverCts = CancellationTokenSource.CreateLinkedTokenSource(hardCancellationToken); var cancellationToken = serverCts.Token; - TerminateAllDDs(); + TerminateAllEngineServers(); InstanceManager GetInstanceManager() => ((Host.Server)server.RealServer).Host.Services.GetRequiredService(); @@ -1315,7 +1327,7 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) .Select(e => instanceClient.Jobs.GetId(e, cancellationToken)) .ToList(); - + jobs = (await ValueTaskExtensions.WhenAll(getTasks)) .Where(x => x.StartedAt.Value > preStartupTime) .ToList(); @@ -1422,7 +1434,7 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest } catch (OperationCanceledException) { } - TerminateAllDDs(); + TerminateAllEngineServers(); } Assert.IsTrue(serverTask.IsCompleted); From 9ed98e2d3e605534eedcd4919974f98cee1cf0be Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 15:42:39 -0400 Subject: [PATCH 083/717] Fix OpenDream installation layout --- .../Components/Engine/OpenDreamInstaller.cs | 95 ++++++++++++++----- 1 file changed, 72 insertions(+), 23 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index cd6cd5eeb76..115ec4f0419 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -24,12 +24,17 @@ namespace Tgstation.Server.Host.Components.Engine class OpenDreamInstaller : EngineInstallerBase { /// - /// The name of the subdirectory used to store the server binaries. + /// The bin directory name. /// - const string InstallationServerDirectory = "server"; + const string BinDir = "bin"; /// - /// The name of the subdirectory used to store the compiler binaries. + /// The OD server directory name. + /// + const string ServerDir = "Content.Server"; + + /// + /// The name of the subdirectory in an installation's used to store the compiler binaries. /// const string InstallationCompilerDirectory = "compiler"; @@ -211,6 +216,7 @@ public override async ValueTask Install(EngineVersion version, string installPat var dotnetPath = dotnetPaths[selectedPathIndex]; + // TODO: https://github.com/OpenDreamProject/OpenDream/issues/1495 int? buildExitCode = null; await HandleExtremelyLongPathOperation( async shortenedPath => @@ -231,27 +237,68 @@ await HandleExtremelyLongPathOperation( if (buildExitCode != 0) throw new JobException("OpenDream build failed!"); - var serverMoveTask = IOManager.MoveDirectory( - IOManager.ConcatPath( - sourcePath, - "bin", - "Content.Server"), - IOManager.ConcatPath( - installPath, - InstallationServerDirectory), - cancellationToken); + async ValueTask MoveBinFiles() + { + var installBinPath = IOManager.ConcatPath(installPath, BinDir); + + await IOManager.CreateDirectory(installBinPath, cancellationToken); + + var serverMoveTask = IOManager.MoveDirectory( + IOManager.ConcatPath( + sourcePath, + BinDir, + ServerDir), + IOManager.ConcatPath( + installBinPath, + ServerDir), + cancellationToken); - var compilerMoveTask = IOManager.MoveDirectory( - IOManager.ConcatPath( - sourcePath, - "bin", - "DMCompiler"), - IOManager.ConcatPath( - installPath, - InstallationCompilerDirectory), - cancellationToken); + var compilerMoveTask = IOManager.MoveDirectory( + IOManager.ConcatPath( + sourcePath, + BinDir, + "DMCompiler"), + IOManager.ConcatPath( + installBinPath, + InstallationCompilerDirectory), + cancellationToken); + + await Task.WhenAll(serverMoveTask, compilerMoveTask); + } + + async ValueTask MoveResources() + { + const string RobustDir = "RobustToolbox"; + const string ResourcesDir = "Resources"; + + var rootMoveTask = IOManager.MoveDirectory( + IOManager.ConcatPath( + sourcePath, + ResourcesDir), + IOManager.ConcatPath( + installPath, + ResourcesDir), + cancellationToken); + var installRobustDir = IOManager.ConcatPath(installPath, RobustDir); + + await IOManager.CreateDirectory(installRobustDir, cancellationToken); + var robustMoveTask = IOManager.MoveDirectory( + IOManager.ConcatPath( + sourcePath, + RobustDir, + ResourcesDir), + IOManager.ConcatPath( + installRobustDir, + ResourcesDir), + cancellationToken); + + await Task.WhenAll(rootMoveTask, robustMoveTask); + } + + var binSetupTask = MoveBinFiles(); + var resourcesMoveTask = MoveResources(); - await Task.WhenAll(serverMoveTask, compilerMoveTask); + await ValueTaskExtensions.WhenAll(binSetupTask, resourcesMoveTask); await IOManager.DeleteDirectory(sourcePath, cancellationToken); } @@ -297,11 +344,13 @@ protected void GetExecutablePaths(string installationPath, out string serverExeP serverExePath = IOManager.ConcatPath( installationPath, - InstallationServerDirectory, + BinDir, + ServerDir, $"OpenDreamServer{exeExtension}"); compilerExePath = IOManager.ConcatPath( installationPath, + BinDir, InstallationCompilerDirectory, $"DMCompiler{exeExtension}"); } From 46a6dfecd78180ba4171fd7d98c5dbbd2a3d2b0d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 15:43:27 -0400 Subject: [PATCH 084/717] Yeah, just commit this debug code for now --- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index ac589da22f6..994cba401fb 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1147,7 +1147,7 @@ await ByondTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellatio await odCompatTests; await odCompatTests; - // Assert.Fail("!!!SUCCESS!!!"); + Assert.Fail("!!!SUCCESS!!!"); // Some earlier linux BYOND versions have a critical bug where replacing the directory in non-basic watchdogs causes the DreamDaemon cwd to change var canRunCompatTests = new PlatformIdentifier().IsWindows; From 421e4f828ee105f1ff6ad954fd6686bcb606520a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 15:51:50 -0400 Subject: [PATCH 085/717] Increase port bind test delay - Run for either engine on Windows --- .../Components/Session/SessionControllerFactory.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 997e8b4e718..1e95d1a1f5c 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -254,8 +254,9 @@ public async ValueTask LaunchNew( // mad this isn't abstracted but whatever if (dmbProvider.EngineVersion.Engine.Value == EngineType.Byond) await CheckPagerIsNotRunning(); - else if (dmbProvider.EngineVersion.Engine.Value == EngineType.OpenDream) - await asyncDelayer.Delay(TimeSpan.FromMilliseconds(1), cancellationToken); // OpenDream is 2fuckingfast and can trip after we bind tested the port + + if (platformIdentifier.IsWindows) + await asyncDelayer.Delay(TimeSpan.FromMilliseconds(500), cancellationToken); // Server can trip after we bind tested the port string outputFilePath = null; var preserveLogFile = true; From 4fbdb9a67dae362cb628bc1f15923c9c08429a99 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 16:02:38 -0400 Subject: [PATCH 086/717] Fix socket lingering --- .../Components/Session/SessionControllerFactory.cs | 4 +--- src/Tgstation.Server.Host/Extensions/SocketExtensions.cs | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 1e95d1a1f5c..8a2a40e28c0 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -217,7 +217,6 @@ public async ValueTask LaunchNew( if (!launchParameters.Port.HasValue) throw new InvalidOperationException("Given port is null!"); - PortBindTest(launchParameters.Port.Value); switch (dmbProvider.CompileJob.MinimumSecurityLevel) { case DreamDaemonSecurity.Ultrasafe: @@ -255,8 +254,7 @@ public async ValueTask LaunchNew( if (dmbProvider.EngineVersion.Engine.Value == EngineType.Byond) await CheckPagerIsNotRunning(); - if (platformIdentifier.IsWindows) - await asyncDelayer.Delay(TimeSpan.FromMilliseconds(500), cancellationToken); // Server can trip after we bind tested the port + PortBindTest(launchParameters.Port.Value); string outputFilePath = null; var preserveLogFile = true; diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs index a9e6a975327..28c94f0ba28 100644 --- a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs @@ -23,6 +23,7 @@ public static void BindTest(ushort port, bool includeIPv6) ProtocolType.Tcp); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); if (includeIPv6) socket.DualMode = true; From ed00399c39613241a3bb00ae61bb429ea421eb51 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 16:05:12 -0400 Subject: [PATCH 087/717] Make some logging engine agnostic --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 24394f4a8b7..3a3db8ef8a4 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -884,10 +884,10 @@ void CheckDDPriority() { var allProcesses = TestLiveServer.GetEngineServerProcessesOnPort(testVersion.Engine.Value, ddPort).Where(x => !x.HasExited).ToList(); if (allProcesses.Count == 0) - Assert.Fail("Expected DreamDaemon to be running here"); + Assert.Fail("Expected engine server to be running here"); if (allProcesses.Count > 1) - Assert.Fail("Multiple DreamDaemon-like processes running!"); + Assert.Fail("Multiple engine server-like processes running!"); using var process = allProcesses[0]; From 0b254fa998206b1938cdc1bc3e8d1e84f4bd435d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 16:09:06 -0400 Subject: [PATCH 088/717] Fix engine port detection under test --- .../Live/TestLiveServer.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 994cba401fb..f4d9295c59d 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -81,7 +81,21 @@ public sealed class TestLiveServer if (port.HasValue) result = result.Where(x => { - if (GetCommandLine(x)?.Contains($"-port {port.Value}") ?? false) + string portString = null; + switch (engineType) + { + case EngineType.OpenDream: + portString = $"--cvar net.port={port.Value}"; + break; + case EngineType.Byond: + portString = $"-port {port.Value}"; + break; + default: + Assert.Fail($"Unknown engine type: {engineType}"); + break; + } + + if (GetCommandLine(x)?.Contains(portString) ?? false) return true; x.Dispose(); From 5d5fbea9004dfc878ae1d480ceb9035efc8bbac0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 17:13:35 -0400 Subject: [PATCH 089/717] Hopefully fixes socket bind testing for the last time --- .../Extensions/SocketExtensions.cs | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs index 28c94f0ba28..baae23e7d7c 100644 --- a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs @@ -1,4 +1,5 @@ -using System.Net; +using System; +using System.Net; using System.Net.Sockets; namespace Tgstation.Server.Host.Extensions @@ -15,24 +16,32 @@ static class SocketExtensions /// If IPV6 should be tested as well. public static void BindTest(ushort port, bool includeIPv6) { - using var socket = new Socket( - includeIPv6 - ? AddressFamily.InterNetworkV6 - : AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.Tcp); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); - if (includeIPv6) - socket.DualMode = true; - - socket.Bind( - new IPEndPoint( + void BindSocket(bool forCleanup) + { + using var socket = new Socket( includeIPv6 - ? IPAddress.IPv6Any - : IPAddress.Any, - port)); + ? AddressFamily.InterNetworkV6 + : AddressFamily.InterNetwork, + SocketType.Stream, + ProtocolType.Tcp); + + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, !forCleanup); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, forCleanup); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); + if (includeIPv6) + socket.DualMode = true; + + socket.Bind( + new IPEndPoint( + includeIPv6 + ? IPAddress.IPv6Any + : IPAddress.Any, + port)); + } + + GC.Collect(Int32.MaxValue, GCCollectionMode.Forced, true, false); + BindSocket(false); + BindSocket(true); } } } From c29982590501cea140e9e5e1b8923f1c87b467eb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 17:18:58 -0400 Subject: [PATCH 090/717] Some `OpenDreamInstaller` unit tests --- .../Engine/TestOpenDreamInstaller.cs | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs diff --git a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs new file mode 100644 index 00000000000..72eef95f230 --- /dev/null +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs @@ -0,0 +1,88 @@ +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Components.Repository; +using Tgstation.Server.Host.Configuration; +using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.System; + +namespace Tgstation.Server.Host.Components.Engine.Tests +{ + [TestClass] + public sealed class TestOpenDreamInstaller + { + [TestMethod] + public async Task TestDownloadsUseSameRepositoryIfItExists() + { + await RepoDownloadTest(false); + } + + [TestMethod] + public async Task TestDownloadsCloneRepositoryIfItDoesntExists() + { + await RepoDownloadTest(true); + } + + static async Task RepoDownloadTest(bool needsClone) + { + var mockGeneralConfigOptions = new Mock>(); + var generalConfig = new GeneralConfiguration(); + Assert.IsNotNull(generalConfig.OpenDreamGitUrl); + mockGeneralConfigOptions.SetupGet(x => x.Value).Returns(generalConfig); + + var cloneAttempts = 0; + var mockRepository = new Mock(); + var mockRepositoryManager = new Mock(); + mockRepositoryManager.Setup(x => x.CloneRepository( + generalConfig.OpenDreamGitUrl, + null, + null, + null, + null, + true, + It.IsAny())) + .Callback(() => ++cloneAttempts) + .Returns(ValueTask.FromResult(needsClone ? mockRepository.Object : null)) + .Verifiable(Times.Exactly(1)); + + mockRepositoryManager.Setup(x => x.LoadRepository( + It.IsAny())) + .Returns(() => + { + Assert.AreEqual(1, cloneAttempts); + return ValueTask.FromResult(mockRepository.Object); + }) + .Verifiable(Times.Exactly(needsClone ? 0 : 1)); + + var installer = new OpenDreamInstaller( + Mock.Of(), + Mock.Of>(), + Mock.Of(), + Mock.Of(), + mockRepositoryManager.Object, + mockGeneralConfigOptions.Object); + + var data = await installer.DownloadVersion( + new EngineVersion + { + Engine = EngineType.OpenDream, + SourceSHA = new string('a', Limits.MaximumCommitShaLength), + }, + null, + CancellationToken.None); + + + Assert.IsNotNull(data); + + mockRepositoryManager.VerifyAll(); + } + } +} From 63aace2c8991647adc421efbf921fafa96c1e4ca Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 17:36:16 -0400 Subject: [PATCH 091/717] Add some repository manager unit tests --- .../Repository/TestRepositoryManager.cs | 133 ++++++++++++++++++ .../Live/TestLiveServer.cs | 4 + 2 files changed, 137 insertions(+) create mode 100644 tests/Tgstation.Server.Host.Tests/Components/Repository/TestRepositoryManager.cs diff --git a/tests/Tgstation.Server.Host.Tests/Components/Repository/TestRepositoryManager.cs b/tests/Tgstation.Server.Host.Tests/Components/Repository/TestRepositoryManager.cs new file mode 100644 index 00000000000..c4a17f51401 --- /dev/null +++ b/tests/Tgstation.Server.Host.Tests/Components/Repository/TestRepositoryManager.cs @@ -0,0 +1,133 @@ +using System; +using System.IO.Pipelines; +using System.Threading; +using System.Threading.Tasks; + +using LibGit2Sharp; + +using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Remora.Rest.Core; + +using Tgstation.Server.Host.Components.Events; +using Tgstation.Server.Host.Configuration; +using Tgstation.Server.Host.IO; + +namespace Tgstation.Server.Host.Components.Repository.Tests +{ + [TestClass] + public sealed class TestRepositoryManager + { + const string TestRepoPath = "adfiwurjwhouerfiunfjdfn"; + + RepositoryManager repositoryManager; + Mock mockRepoFactory; + Mock mockCommands; + Mock mockIOManager; + Mock mockGitRemoteFeaturesFactory; + + [TestInitialize] + public void Initialize() + { + mockIOManager = new Mock(); + mockRepoFactory = new Mock(); + mockCommands = new Mock(); + mockGitRemoteFeaturesFactory = new Mock(); + + mockIOManager.Setup(x => x.ResolvePath()).Returns(TestRepoPath); + + repositoryManager = new RepositoryManager( + mockRepoFactory.Object, + mockCommands.Object, + mockIOManager.Object, + Mock.Of(), + Mock.Of(), + mockGitRemoteFeaturesFactory.Object, + Mock.Of>(), + Mock.Of>(), + new GeneralConfiguration()); + } + + [TestCleanup] + public void TestCleanup() => repositoryManager.Dispose(); + + [TestMethod] + public async Task TestCloneAbortsIfRepoExists() + { + mockIOManager.Setup(x => x.DirectoryExists(TestRepoPath, It.IsAny())).ReturnsAsync(true).Verifiable(); + + using var cloneResult = await repositoryManager.CloneRepository( + new Uri("https://github.com/Cyberboss/common_core"), + null, + null, + null, + null, + false, + CancellationToken.None); + + Assert.IsNull(cloneResult); + + mockIOManager.VerifyAll(); + } + + [TestMethod] + public async Task TestBasicClone() + { + mockIOManager.Setup(x => x.DirectoryExists(TestRepoPath, It.IsAny())).ReturnsAsync(false).Verifiable(); + var mockRepo = new Mock(); + + mockRepoFactory.Setup(x => x.CreateFromPath(TestRepoPath, It.IsAny())).ReturnsAsync(mockRepo.Object).Verifiable(); + + using var cloneResult = await repositoryManager.CloneRepository( + new Uri("https://github.com/Cyberboss/common_core"), + null, + null, + null, + null, + false, + CancellationToken.None); + + Assert.IsNotNull(cloneResult); + + mockRepoFactory.VerifyAll(); + mockIOManager.VerifyAll(); + } + + [TestMethod] + public async Task TestBasicLoad() + { + mockIOManager.Setup(x => x.DirectoryExists(TestRepoPath, It.IsAny())).ReturnsAsync(false).Verifiable(Times.Never); + var mockRepo = new Mock(); + + mockRepoFactory.Setup(x => x.CreateFromPath(TestRepoPath, It.IsAny())).ReturnsAsync(mockRepo.Object).Verifiable(); + + using var loadResult = await repositoryManager.LoadRepository( + CancellationToken.None); + + Assert.IsNotNull(loadResult); + + mockRepoFactory.VerifyAll(); + mockIOManager.VerifyAll(); + } + + [TestMethod] + public async Task TestLoadFailsIfRepoDoesntExist() + { + mockIOManager.Setup(x => x.DirectoryExists(TestRepoPath, It.IsAny())).ReturnsAsync(false).Verifiable(Times.Never); + var mockRepo = new Mock(); + + mockRepoFactory.Setup(x => x.CreateFromPath(TestRepoPath, It.IsAny())).ThrowsAsync(new RepositoryNotFoundException()).Verifiable(); + + using var loadResult = await repositoryManager.LoadRepository( + CancellationToken.None); + + Assert.IsNull(loadResult); + + mockRepoFactory.VerifyAll(); + mockIOManager.VerifyAll(); + } + } +} diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index f4d9295c59d..cbd5181b562 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1006,6 +1006,8 @@ public async Task TestStandardTgsOperation() using var hardCancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(maximumTestMinutes)); var hardCancellationToken = hardCancellationTokenSource.Token; + hardCancellationToken.Register(() => Console.WriteLine("TGS TEST CANCELLED TOKEN DUE TO TIMEOUT")); + ServiceCollectionExtensions.UseAdditionalLoggerProvider(); var failureTask = HardFailLoggerProvider.FailureSource; @@ -1016,6 +1018,7 @@ await Task.WhenAny( if (!internalTask.IsCompleted) { + Console.WriteLine("TGS TEST CANCELLING TOKEN DUE TO ERROR"); hardCancellationTokenSource.Cancel(); try { @@ -1441,6 +1444,7 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest } finally { + Console.WriteLine("TGS TEST CANCELLING TOKEN AS FINAL STEP"); serverCts.Cancel(); try { From 498e5236fdbbe7ce063c41f5004564774ddd3991 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 20:16:06 -0400 Subject: [PATCH 092/717] Fix retesting live catching in-use files sometimes --- .../Live/LiveTestingServer.cs | 6 +++++- .../Tgstation.Server.Tests/Live/TestLiveServer.cs | 14 +++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs index 0f725cf11d0..0d5d0761da2 100644 --- a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs +++ b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs @@ -23,6 +23,7 @@ namespace Tgstation.Server.Tests.Live { sealed class LiveTestingServer : IServer, IDisposable { + static bool needCleanup = false; public static string BaseDirectory { get; } static LiveTestingServer() @@ -32,7 +33,7 @@ static LiveTestingServer() if (string.IsNullOrWhiteSpace(BaseDirectory)) { BaseDirectory = Path.Combine(Path.GetTempPath(), "TGS_INTEGRATION_TEST"); - Cleanup(BaseDirectory).GetAwaiter().GetResult(); + needCleanup = true; } } @@ -74,6 +75,9 @@ static async Task Cleanup(string directory) public LiveTestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth, ushort port = 15010) { + if(needCleanup) + Cleanup(BaseDirectory).GetAwaiter().GetResult(); + Assert.IsTrue(port >= 10000); // for testing bridge request limit Directory = BaseDirectory; diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index cbd5181b562..8b65ade8868 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -127,12 +127,18 @@ private static string GetCommandLine(System.Diagnostics.Process process) } } - static void TerminateAllEngineServers() + static bool TerminateAllEngineServers() { + var result = false; foreach (var enumValue in Enum.GetValues()) foreach (var proc in GetEngineServerProcessesOnPort(enumValue, null)) using (proc) + { proc.Kill(); + result = true; + } + + return result; } static ushort FreeTcpPort(params ushort[] usedPorts) @@ -1081,13 +1087,15 @@ async Task TestTgsInternal(CancellationToken hardCancellationToken) // Inconclusive and not fail because we don't want to unexpectedly kill a dev's BYOND.exe Assert.Inconclusive("Cannot run server test because DreamDaemon will not start headless while the BYOND pager is running!"); } + + if (TerminateAllEngineServers()) + await Task.Delay(TimeSpan.FromSeconds(5)); + using var server = new LiveTestingServer(null, true); using var serverCts = CancellationTokenSource.CreateLinkedTokenSource(hardCancellationToken); var cancellationToken = serverCts.Token; - TerminateAllEngineServers(); - InstanceManager GetInstanceManager() => ((Host.Server)server.RealServer).Host.Services.GetRequiredService(); // main run From 64baf37d641ecc1869e3e10dcaa13b94a28a4c84 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 20:49:24 -0400 Subject: [PATCH 093/717] Bind conflicts again! --- src/Tgstation.Server.Host/Extensions/SocketExtensions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs index baae23e7d7c..aeff082638b 100644 --- a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs @@ -42,6 +42,7 @@ void BindSocket(bool forCleanup) GC.Collect(Int32.MaxValue, GCCollectionMode.Forced, true, false); BindSocket(false); BindSocket(true); + GC.Collect(Int32.MaxValue, GCCollectionMode.Forced, true, false); } } } From 89ad9902124431ed453c645eaabfe7cb5dc9379a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 20:49:42 -0400 Subject: [PATCH 094/717] Fix test assumption confusion --- tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 31048283e5c..0a8486713d4 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -208,8 +208,6 @@ await Task.WhenAll( Assert.AreEqual(compatVersion.Version, activeVersion.EngineVersion.Version); Assert.AreEqual(compatVersion.Engine, activeVersion.EngineVersion.Engine); Assert.AreEqual(1, activeVersion.EngineVersion.CustomIteration); - - compatVersion = activeVersion.EngineVersion; } var configSetupTask = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata).SetupDMApiTests(cancellationToken); From 5fdaaccd680e80c898340462b43a59ade8e3dd5f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 20:50:00 -0400 Subject: [PATCH 095/717] Use the new system for finding the topic port --- .../Live/Instance/WatchdogTest.cs | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 3a3db8ef8a4..2f838c0f766 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -8,11 +8,13 @@ using Newtonsoft.Json; using System; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; +using System.Reflection; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -786,6 +788,18 @@ async Task ValidateTopicLimits(CancellationToken cancellationToken) Assert.AreEqual(DMApiConstants.MaximumTopicResponseLength, (uint)lastSize); } + ushort FindTopicPort() + { + using var instanceReference = instanceManager.GetInstanceReference(instanceClient.Metadata); + var watchdog = instanceReference.Watchdog; + + var sessionObj = watchdog.GetType().GetProperty("Server", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(watchdog); + Assert.IsNotNull(sessionObj); + + var session = (ISessionController)sessionObj; + return session.ReattachInformation.Port; + } + // - Uses instance manager concrete // - Injects a custom bridge handler into the bridge registrar and makes the test hack into the DMAPI and change its access_identifier async Task WhiteBoxChatCommandTest(CancellationToken cancellationToken) @@ -1104,15 +1118,16 @@ bool KillDD(bool require) return ddProc != null; } - public Task TellWorldToReboot(CancellationToken cancellationToken) => TellWorldToReboot2(instanceClient, topicClient, ddPort, cancellationToken); - public static async Task TellWorldToReboot2(IInstanceClient instanceClient, ITopicClient topicClient, ushort ddPort, CancellationToken cancellationToken) + public Task TellWorldToReboot(CancellationToken cancellationToken) => TellWorldToReboot2(instanceClient, topicClient, FindTopicPort(), cancellationToken); + public static async Task TellWorldToReboot2(IInstanceClient instanceClient, ITopicClient topicClient, ushort topicPort, CancellationToken cancellationToken) { var daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.IsNotNull(daemonStatus.StagedCompileJob); var initialCompileJob = daemonStatus.ActiveCompileJob; System.Console.WriteLine("TEST: Sending world reboot topic..."); - var result = await topicClient.SendTopic(IPAddress.Loopback, "tgs_integration_test_special_tactics=1", ddPort, cancellationToken); + + var result = await topicClient.SendTopic(IPAddress.Loopback, "tgs_integration_test_special_tactics=1", topicPort, cancellationToken); Assert.AreEqual("ack", result.StringData); using var tempCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); From 2e53c084d800d967126eb3ac16c10f4560f1f30d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 21:19:52 -0400 Subject: [PATCH 096/717] Cargo cult fix for bind test --- .../Extensions/SocketExtensions.cs | 45 ++++++++----------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs index aeff082638b..71645f9dc5d 100644 --- a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs @@ -1,5 +1,4 @@ -using System; -using System.Net; +using System.Net; using System.Net.Sockets; namespace Tgstation.Server.Host.Extensions @@ -16,33 +15,27 @@ static class SocketExtensions /// If IPV6 should be tested as well. public static void BindTest(ushort port, bool includeIPv6) { - void BindSocket(bool forCleanup) - { - using var socket = new Socket( - includeIPv6 - ? AddressFamily.InterNetworkV6 - : AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.Tcp); + using var socket = new Socket( + includeIPv6 + ? AddressFamily.InterNetworkV6 + : AddressFamily.InterNetwork, + SocketType.Stream, + ProtocolType.Tcp); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, !forCleanup); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, forCleanup); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); - if (includeIPv6) - socket.DualMode = true; + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); + if (includeIPv6) + socket.DualMode = true; - socket.Bind( - new IPEndPoint( - includeIPv6 - ? IPAddress.IPv6Any - : IPAddress.Any, - port)); - } + socket.Bind( + new IPEndPoint( + includeIPv6 + ? IPAddress.IPv6Any + : IPAddress.Any, + port)); - GC.Collect(Int32.MaxValue, GCCollectionMode.Forced, true, false); - BindSocket(false); - BindSocket(true); - GC.Collect(Int32.MaxValue, GCCollectionMode.Forced, true, false); + socket.Close(); } } } From 15a3c12211eee0591256e674b610e52ec11c638c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 21:29:21 -0400 Subject: [PATCH 097/717] Fix more bad ports with test topics --- .../Live/Instance/WatchdogTest.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 2f838c0f766..f1777ee267a 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -213,7 +213,7 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) var topicRequestResult = await topicClient.SendTopic( IPAddress.Loopback, $"shadow_wizard_money_gang=1", - ddPort, + FindTopicPort(), cancellationToken); Assert.IsNotNull(topicRequestResult); @@ -345,7 +345,7 @@ async Task SendChatOverloadCommand(CancellationToken cancellationToken) var topicRequestResult = await topicClient.SendTopic( IPAddress.Loopback, $"tgs_integration_test_tactics5=1", - ddPort, + FindTopicPort(), cancellationToken); Assert.IsNotNull(topicRequestResult); @@ -561,7 +561,7 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke var topicRequestResult = await topicClient.SendTopic( IPAddress.Loopback, $"tgs_integration_test_tactics8=1", - ddPort, + FindTopicPort(), cancellationToken); Assert.IsNotNull(topicRequestResult); @@ -673,7 +673,7 @@ async Task WhiteBoxValidateBridgeRequestLimitAndTestChunking(CancellationToken c System.Console.WriteLine("TEST: Sending Bridge tests topic..."); - var bridgeTestTopicResult = await topicClient.SendTopic(IPAddress.Loopback, $"tgs_integration_test_tactics2={accessIdentifier}", ddPort, cancellationToken); + var bridgeTestTopicResult = await topicClient.SendTopic(IPAddress.Loopback, $"tgs_integration_test_tactics2={accessIdentifier}", FindTopicPort(), cancellationToken); Assert.AreEqual("ack2", bridgeTestTopicResult.StringData); await bridgeTestsTcs.Task.WaitAsync(cancellationToken); @@ -726,7 +726,7 @@ async Task ValidateTopicLimits(CancellationToken cancellationToken) topicRequestResult = await topicClient.SendTopic( IPAddress.Loopback, $"tgs_integration_test_tactics3={topicClient.SanitizeString(JsonConvert.SerializeObject(topic, DMApiConstants.SerializerSettings))}", - ddPort, + FindTopicPort(), cancellationToken); } catch (ArgumentOutOfRangeException) @@ -767,7 +767,7 @@ async Task ValidateTopicLimits(CancellationToken cancellationToken) var topicRequestResult = await topicClient.SendTopic( IPAddress.Loopback, $"tgs_integration_test_tactics4={topicClient.SanitizeString(currentSize.ToString())}", - ddPort, + FindTopicPort(), cancellationToken); if (topicRequestResult.ResponseType != TopicResponseType.StringResponse From f615a34e7792389eabdc96f9b31ea02ff72d04bd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 21:31:37 -0400 Subject: [PATCH 098/717] Rage comments --- src/Tgstation.Server.Host/Extensions/SocketExtensions.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs index 71645f9dc5d..8c61aa91349 100644 --- a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs @@ -35,6 +35,12 @@ public static void BindTest(ushort port, bool includeIPv6) : IPAddress.Any, port)); + // BY ALL KNOWN LAWS OF AVIATION THERE'S NO FUCKING WAY THIS CALL SHOULD BE NECESSARY + // YET, WITHOUT IT, OPENDREAM WILL RUN INTO PORT REUSE ISSUES + // CTRL-CLICK IT THOUGH, ALL IT DOES IS CALL THE GODDAMN FUCKING DISPOSE() + // AND THE DISPOSE() CAN'T BE DOUBLE CALLED DUE TO ATOMICS + // REMOVE IT THOUGH, RUN THE TESTS ON A FAST PC AND THEY WILL FAIL DUE TO ADDRESS REUSE + // HORY FUCKING SHIT socket.Close(); } } From 37c6e1bfe97c7a4612983d50ce175d2b850cc9cb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 22:39:21 -0400 Subject: [PATCH 099/717] Slight expression extraction to help with debugging --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index f1777ee267a..7775e9eb255 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -879,7 +879,8 @@ static void CheckEmbedsTest(MessageContent embedsResponse, DateTimeOffset startT Assert.AreEqual("Dominion", embedsResponse.Embed.Author?.Name); Assert.AreEqual("https://github.com/Cyberboss", embedsResponse.Embed.Author.Url); Assert.IsTrue(DateTimeOffset.TryParse(embedsResponse.Embed.Timestamp, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var timestamp)); - Assert.IsTrue(startTime < timestamp && endTime > timestamp); + var timestampCheck = startTime < timestamp && endTime > timestamp; + Assert.IsTrue(timestampCheck); Assert.AreEqual("https://github.com/tgstation/tgstation-server", embedsResponse.Embed.Url); Assert.AreEqual(3, embedsResponse.Embed.Fields?.Count); Assert.AreEqual("field1", embedsResponse.Embed.Fields.ElementAt(0).Name); From 068f7566b2c373b6c7fd3676cb9d25af7ba89218 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 15 Oct 2023 23:40:58 -0400 Subject: [PATCH 100/717] FUCK ADDRESS REUSE ERRORS --- .../Components/Session/SessionControllerFactory.cs | 8 +++++--- src/Tgstation.Server.Host/Extensions/SocketExtensions.cs | 8 -------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 8a2a40e28c0..6daf9cb6d42 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -217,6 +217,7 @@ public async ValueTask LaunchNew( if (!launchParameters.Port.HasValue) throw new InvalidOperationException("Given port is null!"); + PortBindTest(launchParameters.Port.Value); switch (dmbProvider.CompileJob.MinimumSecurityLevel) { case DreamDaemonSecurity.Ultrasafe: @@ -251,10 +252,11 @@ public async ValueTask LaunchNew( dmbProvider.CompileJob.Id); // mad this isn't abstracted but whatever - if (dmbProvider.EngineVersion.Engine.Value == EngineType.Byond) + var engineType = dmbProvider.EngineVersion.Engine.Value; + if (engineType == EngineType.Byond) await CheckPagerIsNotRunning(); - - PortBindTest(launchParameters.Port.Value); + else if (engineType == EngineType.OpenDream && platformIdentifier.IsWindows) + await asyncDelayer.Delay(TimeSpan.FromSeconds(1), cancellationToken); // prevent socket reuse after bind test string outputFilePath = null; var preserveLogFile = true; diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs index 8c61aa91349..948aedbc72e 100644 --- a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs @@ -34,14 +34,6 @@ public static void BindTest(ushort port, bool includeIPv6) ? IPAddress.IPv6Any : IPAddress.Any, port)); - - // BY ALL KNOWN LAWS OF AVIATION THERE'S NO FUCKING WAY THIS CALL SHOULD BE NECESSARY - // YET, WITHOUT IT, OPENDREAM WILL RUN INTO PORT REUSE ISSUES - // CTRL-CLICK IT THOUGH, ALL IT DOES IS CALL THE GODDAMN FUCKING DISPOSE() - // AND THE DISPOSE() CAN'T BE DOUBLE CALLED DUE TO ATOMICS - // REMOVE IT THOUGH, RUN THE TESTS ON A FAST PC AND THEY WILL FAIL DUE TO ADDRESS REUSE - // HORY FUCKING SHIT - socket.Close(); } } } From 257b7beaa8ae9157f5dd23339b55ecb88c8f37f1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 01:07:21 -0400 Subject: [PATCH 101/717] Make reboots a lot faster --- tests/DMAPI/LongRunning/Test.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/DMAPI/LongRunning/Test.dm b/tests/DMAPI/LongRunning/Test.dm index bed428eceb2..c5fb896921c 100644 --- a/tests/DMAPI/LongRunning/Test.dm +++ b/tests/DMAPI/LongRunning/Test.dm @@ -203,7 +203,7 @@ var/received_health_check = FALSE set waitfor = FALSE world.TgsChatBroadcast(new /datum/tgs_message_content("Rebooting after 3 seconds")); world.log << "About to sleep. sleep_offline: [world.sleep_offline]" - sleep(30) + sleep(1) world.log << "Done sleep, calling Reboot" world.Reboot() From 71d803ccc4180e12816b68d615dd153e49583857 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 01:07:34 -0400 Subject: [PATCH 102/717] More OD test fixes --- .../Live/Instance/WatchdogTest.cs | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 7775e9eb255..1d5a1e593be 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -231,7 +231,16 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) await TellWorldToReboot(cancellationToken); - currentStatus = await instanceClient.DreamDaemon.Read(cancellationToken); + if (testVersion.Engine == EngineType.OpenDream) + do + { + await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); + currentStatus = await instanceClient.DreamDaemon.Read(cancellationToken); + } + while (currentStatus.Status == WatchdogStatus.Restoring); + else + currentStatus = await instanceClient.DreamDaemon.Read(cancellationToken); + Assert.AreEqual(WatchdogStatus.Online, currentStatus.Status); Assert.IsNull(currentStatus.StagedCompileJob); Assert.AreEqual(expectedStaged.Id, currentStatus.ActiveCompileJob.Id); @@ -242,8 +251,6 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationToken cancellationToken) { - var testCustomVersion = testVersion.Version; - var testCustomRevision = 1; var currentByond = await instanceClient.Byond.ActiveVersion(cancellationToken); Assert.IsNotNull(currentByond); Assert.AreEqual(testVersion, currentByond.EngineVersion); @@ -254,9 +261,10 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo { EngineVersion = new EngineVersion { - Version = testCustomVersion, + Version = testVersion.Version, + SourceSHA = testVersion.SourceSHA, Engine = testVersion.Engine, - CustomIteration = testCustomRevision, + CustomIteration = 1, } }, null, @@ -310,9 +318,10 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo { EngineVersion = new EngineVersion { - Version = testCustomVersion, + Version = testVersion.Version, Engine = testVersion.Engine, - CustomIteration = testCustomRevision, + SourceSHA = testVersion.SourceSHA, + CustomIteration = 1, } }, null, From 4fca3242ce2fc714dcafb00327a4ee86a2c4ff1a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 01:07:43 -0400 Subject: [PATCH 103/717] Remove debug code --- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 8b65ade8868..229bdeade64 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1171,9 +1171,6 @@ await ByondTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellatio if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization await odCompatTests; - await odCompatTests; - Assert.Fail("!!!SUCCESS!!!"); - // Some earlier linux BYOND versions have a critical bug where replacing the directory in non-basic watchdogs causes the DreamDaemon cwd to change var canRunCompatTests = new PlatformIdentifier().IsWindows; var compatTests = canRunCompatTests From bb5fd19eaee514e48566edd2e1f1a7f40436d2d6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 01:08:52 -0400 Subject: [PATCH 104/717] Fix other failing test --- tests/Tgstation.Server.Tests/TestVersions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 646a362d22e..cba96b07e00 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -450,7 +450,7 @@ static async Task TestMapThreadsVersion( await byondInstaller.Install(engineVersion, tempPath, default); - var binPath = (string)typeof(ByondInstallerBase).GetField("BinPath", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); + var binPath = (string)typeof(ByondInstallerBase).GetField("ByondBinPath", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); var ddNameFunc = installerType.GetMethod("GetDreamDaemonName", BindingFlags.Instance | BindingFlags.NonPublic); var supportsCli = false; var argArray = new object[] { engineVersion.Version, supportsCli }; From b397b05f60d9459affc5284d2e42ca0714253047 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 01:18:24 -0400 Subject: [PATCH 105/717] This reboot was too fast --- tests/DMAPI/LongRunning/Test.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/DMAPI/LongRunning/Test.dm b/tests/DMAPI/LongRunning/Test.dm index c5fb896921c..bed428eceb2 100644 --- a/tests/DMAPI/LongRunning/Test.dm +++ b/tests/DMAPI/LongRunning/Test.dm @@ -203,7 +203,7 @@ var/received_health_check = FALSE set waitfor = FALSE world.TgsChatBroadcast(new /datum/tgs_message_content("Rebooting after 3 seconds")); world.log << "About to sleep. sleep_offline: [world.sleep_offline]" - sleep(1) + sleep(30) world.log << "Done sleep, calling Reboot" world.Reboot() From 512aa8f7ae5c2b4decf5e47866aa6469dbcad083 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 01:20:25 -0400 Subject: [PATCH 106/717] Fix test cleaning --- tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs index 0d5d0761da2..aff760753e2 100644 --- a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs +++ b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs @@ -75,8 +75,11 @@ static async Task Cleanup(string directory) public LiveTestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth, ushort port = 15010) { - if(needCleanup) + if (needCleanup) + { + needCleanup = false; Cleanup(BaseDirectory).GetAwaiter().GetResult(); + } Assert.IsTrue(port >= 10000); // for testing bridge request limit Directory = BaseDirectory; From 0413f8b676c244511c08a15750f4839adb7d7e53 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 01:30:08 -0400 Subject: [PATCH 107/717] Fix test location --- .../Models/{ => Internal}/TestEngineVersion.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) rename tests/Tgstation.Server.Api.Tests/Models/{ => Internal}/TestEngineVersion.cs (94%) diff --git a/tests/Tgstation.Server.Api.Tests/Models/TestEngineVersion.cs b/tests/Tgstation.Server.Api.Tests/Models/Internal/TestEngineVersion.cs similarity index 94% rename from tests/Tgstation.Server.Api.Tests/Models/TestEngineVersion.cs rename to tests/Tgstation.Server.Api.Tests/Models/Internal/TestEngineVersion.cs index eb7a58e62d9..a426927b01f 100644 --- a/tests/Tgstation.Server.Api.Tests/Models/TestEngineVersion.cs +++ b/tests/Tgstation.Server.Api.Tests/Models/Internal/TestEngineVersion.cs @@ -2,9 +2,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Tgstation.Server.Api.Models.Internal; - -namespace Tgstation.Server.Api.Models.Tests +namespace Tgstation.Server.Api.Models.Internal.Tests { [TestClass] public sealed class TestEngineVersion From 05c8afc54e4d79b086a6938ca57fc0ac28f5ab6a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 01:32:15 -0400 Subject: [PATCH 108/717] Remove unused field --- .../Controllers/ByondController.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs index 22dcc4f2c1f..b085f173922 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using Tgstation.Server.Api; using Tgstation.Server.Api.Models; @@ -15,7 +14,6 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Api.Rights; using Tgstation.Server.Host.Components; -using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.Jobs; @@ -41,11 +39,6 @@ public sealed class ByondController : InstanceRequiredController /// readonly IFileTransferTicketProvider fileTransferService; - /// - /// The for the . - /// - readonly GeneralConfiguration generalConfiguration; - /// /// Remove the from a given if present. /// @@ -62,15 +55,13 @@ public sealed class ByondController : InstanceRequiredController /// The for the . /// The value of . /// The value of . - /// The containing the value of . public ByondController( IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ILogger logger, IInstanceManager instanceManager, IJobManager jobManager, - IFileTransferTicketProvider fileTransferService, - IOptions generalConfigurationOptions) + IFileTransferTicketProvider fileTransferService) : base( databaseContext, authenticationContextFactory, @@ -79,7 +70,6 @@ public ByondController( { this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); this.fileTransferService = fileTransferService ?? throw new ArgumentNullException(nameof(fileTransferService)); - generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } /// From 9a3d02a244059cc26ed5091c1727e1110f8bf75a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 01:44:56 -0400 Subject: [PATCH 109/717] BYOND -> Engine nomenclature changes --- .../Models/Internal/InstancePermissionSet.cs | 15 +++- ...quest.cs => EngineVersionDeleteRequest.cs} | 2 +- ...sionRequest.cs => EngineVersionRequest.cs} | 2 +- ...llResponse.cs => EngineInstallResponse.cs} | 10 +-- .../{ByondResponse.cs => EngineResponse.cs} | 2 +- .../{ByondRights.cs => EngineRights.cs} | 4 +- .../Rights/RightsHelper.cs | 2 +- src/Tgstation.Server.Api/Rights/RightsType.cs | 4 +- src/Tgstation.Server.Api/Routes.cs | 4 +- .../{ByondClient.cs => EngineClient.cs} | 26 +++--- .../Components/IByondClient.cs | 48 ----------- .../Components/IEngineClient.cs | 48 +++++++++++ .../Components/IInstanceClient.cs | 4 +- .../Components/InstanceClient.cs | 4 +- ...ByondController.cs => EngineController.cs} | 80 +++++++++---------- .../Controllers/InstanceController.cs | 6 +- .../InstancePermissionSetController.cs | 4 +- .../Controllers/TgsAuthorizeAttribute.cs | 6 +- .../Models/InstancePermissionSet.cs | 2 +- .../Rights/TestRights.cs | 6 +- .../TestApiClient.cs | 8 +- .../Security/TestAuthenticationContext.cs | 4 +- .../Live/Instance/ByondTest.cs | 32 ++++---- .../Live/Instance/InstanceTest.cs | 8 +- .../Live/Instance/WatchdogTest.cs | 30 +++---- tests/Tgstation.Server.Tests/TestDatabase.cs | 2 +- .../Program.cs | 6 +- 27 files changed, 188 insertions(+), 181 deletions(-) rename src/Tgstation.Server.Api/Models/Request/{ByondVersionDeleteRequest.cs => EngineVersionDeleteRequest.cs} (89%) rename src/Tgstation.Server.Api/Models/Request/{ByondVersionRequest.cs => EngineVersionRequest.cs} (91%) rename src/Tgstation.Server.Api/Models/Response/{ByondInstallResponse.cs => EngineInstallResponse.cs} (51%) rename src/Tgstation.Server.Api/Models/Response/{ByondResponse.cs => EngineResponse.cs} (91%) rename src/Tgstation.Server.Api/Rights/{ByondRights.cs => EngineRights.cs} (94%) rename src/Tgstation.Server.Client/Components/{ByondClient.cs => EngineClient.cs} (50%) delete mode 100644 src/Tgstation.Server.Client/Components/IByondClient.cs create mode 100644 src/Tgstation.Server.Client/Components/IEngineClient.cs rename src/Tgstation.Server.Host/Controllers/{ByondController.cs => EngineController.cs} (82%) diff --git a/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs b/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs index ad0e4d3f1d0..1564e5949a0 100644 --- a/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs +++ b/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs @@ -1,4 +1,6 @@ -using System.ComponentModel.DataAnnotations; +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using Tgstation.Server.Api.Rights; @@ -22,10 +24,17 @@ public abstract class InstancePermissionSet public InstancePermissionSetRights? InstancePermissionSetRights { get; set; } /// - /// The of the . + /// The of the . + /// + [NotMapped] + public EngineRights? EngineRights { get; set; } + + /// + /// The legacy of the . /// [Required] - public ByondRights? ByondRights { get; set; } + [Obsolete("Use EngineRights instead")] + public EngineRights? ByondRights { get; set; } /// /// The of the . diff --git a/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs b/src/Tgstation.Server.Api/Models/Request/EngineVersionDeleteRequest.cs similarity index 89% rename from src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs rename to src/Tgstation.Server.Api/Models/Request/EngineVersionDeleteRequest.cs index 692c270a5e7..d9526eef999 100644 --- a/src/Tgstation.Server.Api/Models/Request/ByondVersionDeleteRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/EngineVersionDeleteRequest.cs @@ -5,7 +5,7 @@ namespace Tgstation.Server.Api.Models.Request /// /// A request to delete a specific . /// - public class ByondVersionDeleteRequest + public class EngineVersionDeleteRequest { /// /// The to delete. diff --git a/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs b/src/Tgstation.Server.Api/Models/Request/EngineVersionRequest.cs similarity index 91% rename from src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs rename to src/Tgstation.Server.Api/Models/Request/EngineVersionRequest.cs index de00f22994c..a1a045a73a9 100644 --- a/src/Tgstation.Server.Api/Models/Request/ByondVersionRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/EngineVersionRequest.cs @@ -5,7 +5,7 @@ namespace Tgstation.Server.Api.Models.Request /// /// A request to switch to a given . /// - public sealed class ByondVersionRequest + public sealed class EngineVersionRequest { /// /// The to switch to. diff --git a/src/Tgstation.Server.Api/Models/Response/ByondInstallResponse.cs b/src/Tgstation.Server.Api/Models/Response/EngineInstallResponse.cs similarity index 51% rename from src/Tgstation.Server.Api/Models/Response/ByondInstallResponse.cs rename to src/Tgstation.Server.Api/Models/Response/EngineInstallResponse.cs index 1b66a459b45..7972f5d6217 100644 --- a/src/Tgstation.Server.Api/Models/Response/ByondInstallResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/EngineInstallResponse.cs @@ -1,14 +1,12 @@ -using System; - -namespace Tgstation.Server.Api.Models.Response +namespace Tgstation.Server.Api.Models.Response { /// - /// Represents a BYOND installation. is used to upload custom BYOND version zip files, though must still be set. + /// Represents an engine installation job. is used to upload custom version zip files. /// - public sealed class ByondInstallResponse : FileTicketResponse + public sealed class EngineInstallResponse : FileTicketResponse { /// - /// The being used to install a new . + /// The being used to install a new . /// [ResponseOptions] public JobResponse? InstallJob { get; set; } diff --git a/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs b/src/Tgstation.Server.Api/Models/Response/EngineResponse.cs similarity index 91% rename from src/Tgstation.Server.Api/Models/Response/ByondResponse.cs rename to src/Tgstation.Server.Api/Models/Response/EngineResponse.cs index aff07a3954d..b9de3753fa9 100644 --- a/src/Tgstation.Server.Api/Models/Response/ByondResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/EngineResponse.cs @@ -5,7 +5,7 @@ namespace Tgstation.Server.Api.Models.Response /// /// Represents an installed . /// - public sealed class ByondResponse + public sealed class EngineResponse { /// /// The represented . If that indicates none were found. diff --git a/src/Tgstation.Server.Api/Rights/ByondRights.cs b/src/Tgstation.Server.Api/Rights/EngineRights.cs similarity index 94% rename from src/Tgstation.Server.Api/Rights/ByondRights.cs rename to src/Tgstation.Server.Api/Rights/EngineRights.cs index 6e20a62b3b5..93f8c39dd9e 100644 --- a/src/Tgstation.Server.Api/Rights/ByondRights.cs +++ b/src/Tgstation.Server.Api/Rights/EngineRights.cs @@ -3,10 +3,10 @@ namespace Tgstation.Server.Api.Rights { /// - /// Rights for BYOND version management. + /// Rights for engine version management. /// [Flags] - public enum ByondRights : ulong + public enum EngineRights : ulong { /// /// User has no rights. diff --git a/src/Tgstation.Server.Api/Rights/RightsHelper.cs b/src/Tgstation.Server.Api/Rights/RightsHelper.cs index eb33954a48a..9df78bb81ba 100644 --- a/src/Tgstation.Server.Api/Rights/RightsHelper.cs +++ b/src/Tgstation.Server.Api/Rights/RightsHelper.cs @@ -17,7 +17,7 @@ public static class RightsHelper { RightsType.Administration, typeof(AdministrationRights) }, { RightsType.InstanceManager, typeof(InstanceManagerRights) }, { RightsType.Repository, typeof(RepositoryRights) }, - { RightsType.Byond, typeof(ByondRights) }, + { RightsType.Engine, typeof(EngineRights) }, { RightsType.DreamMaker, typeof(DreamMakerRights) }, { RightsType.DreamDaemon, typeof(DreamDaemonRights) }, { RightsType.ChatBots, typeof(ChatBotRights) }, diff --git a/src/Tgstation.Server.Api/Rights/RightsType.cs b/src/Tgstation.Server.Api/Rights/RightsType.cs index ae40fe46be9..1959a56e5b1 100644 --- a/src/Tgstation.Server.Api/Rights/RightsType.cs +++ b/src/Tgstation.Server.Api/Rights/RightsType.cs @@ -21,9 +21,9 @@ public enum RightsType : ulong Repository, /// - /// + /// /// - Byond, + Engine, /// /// diff --git a/src/Tgstation.Server.Api/Routes.cs b/src/Tgstation.Server.Api/Routes.cs index ab8bd05c23f..20b52be7abd 100644 --- a/src/Tgstation.Server.Api/Routes.cs +++ b/src/Tgstation.Server.Api/Routes.cs @@ -38,9 +38,9 @@ public static class Routes public const string InstanceManager = Root + "Instance"; /// - /// The BYOND controller. + /// The engine controller. /// - public const string Byond = Root + "Byond"; + public const string Engine = Root + "Engine"; /// /// The git repository controller. diff --git a/src/Tgstation.Server.Client/Components/ByondClient.cs b/src/Tgstation.Server.Client/Components/EngineClient.cs similarity index 50% rename from src/Tgstation.Server.Client/Components/ByondClient.cs rename to src/Tgstation.Server.Client/Components/EngineClient.cs index e171af7860e..9f062995bb2 100644 --- a/src/Tgstation.Server.Client/Components/ByondClient.cs +++ b/src/Tgstation.Server.Client/Components/EngineClient.cs @@ -11,46 +11,46 @@ namespace Tgstation.Server.Client.Components { - /// - sealed class ByondClient : PaginatedClient, IByondClient + /// + sealed class EngineClient : PaginatedClient, IEngineClient { /// - /// The for the . + /// The for the . /// readonly Instance instance; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The for the . /// The value of . - public ByondClient(IApiClient apiClient, Instance instance) + public EngineClient(IApiClient apiClient, Instance instance) : base(apiClient) { this.instance = instance ?? throw new ArgumentNullException(nameof(instance)); } /// - public ValueTask ActiveVersion(CancellationToken cancellationToken) => ApiClient.Read(Routes.Byond, instance.Id!.Value, cancellationToken); + public ValueTask ActiveVersion(CancellationToken cancellationToken) => ApiClient.Read(Routes.Engine, instance.Id!.Value, cancellationToken); /// - public ValueTask DeleteVersion(ByondVersionDeleteRequest deleteRequest, CancellationToken cancellationToken) - => ApiClient.Delete(Routes.Byond, deleteRequest, instance.Id!.Value, cancellationToken); + public ValueTask DeleteVersion(EngineVersionDeleteRequest deleteRequest, CancellationToken cancellationToken) + => ApiClient.Delete(Routes.Engine, deleteRequest, instance.Id!.Value, cancellationToken); /// - public ValueTask> InstalledVersions(PaginationSettings? paginationSettings, CancellationToken cancellationToken) - => ReadPaged(paginationSettings, Routes.ListRoute(Routes.Byond), instance.Id, cancellationToken); + public ValueTask> InstalledVersions(PaginationSettings? paginationSettings, CancellationToken cancellationToken) + => ReadPaged(paginationSettings, Routes.ListRoute(Routes.Engine), instance.Id, cancellationToken); /// - public async ValueTask SetActiveVersion(ByondVersionRequest installRequest, Stream? zipFileStream, CancellationToken cancellationToken) + public async ValueTask SetActiveVersion(EngineVersionRequest installRequest, Stream? zipFileStream, CancellationToken cancellationToken) { if (installRequest == null) throw new ArgumentNullException(nameof(installRequest)); if (installRequest.UploadCustomZip == true && zipFileStream == null) throw new ArgumentNullException(nameof(zipFileStream)); - var result = await ApiClient.Update( - Routes.Byond, + var result = await ApiClient.Update( + Routes.Engine, installRequest, instance.Id!.Value, cancellationToken) diff --git a/src/Tgstation.Server.Client/Components/IByondClient.cs b/src/Tgstation.Server.Client/Components/IByondClient.cs deleted file mode 100644 index bde6e04535c..00000000000 --- a/src/Tgstation.Server.Client/Components/IByondClient.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -using Tgstation.Server.Api.Models.Request; -using Tgstation.Server.Api.Models.Response; - -namespace Tgstation.Server.Client.Components -{ - /// - /// For managing the installation. - /// - public interface IByondClient - { - /// - /// Get the active information. - /// - /// The for the operation. - /// A resulting in the active information. - ValueTask ActiveVersion(CancellationToken cancellationToken); - - /// - /// Get all installed s. - /// - /// The optional for the operation. - /// The for the operation. - /// A resulting in an of installed s. - ValueTask> InstalledVersions(PaginationSettings? paginationSettings, CancellationToken cancellationToken); - - /// - /// Updates the active BYOND version. - /// - /// The . - /// The for the .zip file if is . Will be ignored if it is . - /// The for the operation. - /// A resulting in the updated information. - ValueTask SetActiveVersion(ByondVersionRequest installRequest, Stream? zipFileStream, CancellationToken cancellationToken); - - /// - /// Starts a jobs to delete a specific BYOND version. - /// - /// The specifying the version to delete. - /// The for the operation. - /// A resulting in the for the delete job. - ValueTask DeleteVersion(ByondVersionDeleteRequest deleteRequest, CancellationToken cancellationToken); - } -} diff --git a/src/Tgstation.Server.Client/Components/IEngineClient.cs b/src/Tgstation.Server.Client/Components/IEngineClient.cs new file mode 100644 index 00000000000..d097b72f3a4 --- /dev/null +++ b/src/Tgstation.Server.Client/Components/IEngineClient.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +using Tgstation.Server.Api.Models.Request; +using Tgstation.Server.Api.Models.Response; + +namespace Tgstation.Server.Client.Components +{ + /// + /// For managing the engine installations. + /// + public interface IEngineClient + { + /// + /// Get the active . + /// + /// The for the operation. + /// A resulting in the . + ValueTask ActiveVersion(CancellationToken cancellationToken); + + /// + /// Get all installed s. + /// + /// The optional for the operation. + /// The for the operation. + /// A resulting in an of installed s. + ValueTask> InstalledVersions(PaginationSettings? paginationSettings, CancellationToken cancellationToken); + + /// + /// Updates the active engine version. + /// + /// The . + /// The for the .zip file if is . Will be ignored if it is . + /// The for the operation. + /// A resulting in the . + ValueTask SetActiveVersion(EngineVersionRequest installRequest, Stream? zipFileStream, CancellationToken cancellationToken); + + /// + /// Starts a job to delete a specific engine version. + /// + /// The specifying the to delete. + /// The for the operation. + /// A resulting in the for the delete job. + ValueTask DeleteVersion(EngineVersionDeleteRequest deleteRequest, CancellationToken cancellationToken); + } +} diff --git a/src/Tgstation.Server.Client/Components/IInstanceClient.cs b/src/Tgstation.Server.Client/Components/IInstanceClient.cs index 564e089e200..9799b5699b2 100644 --- a/src/Tgstation.Server.Client/Components/IInstanceClient.cs +++ b/src/Tgstation.Server.Client/Components/IInstanceClient.cs @@ -13,9 +13,9 @@ public interface IInstanceClient Instance Metadata { get; } /// - /// Access the . + /// Access the . /// - IByondClient Byond { get; } + IEngineClient Engine { get; } /// /// Access the . diff --git a/src/Tgstation.Server.Client/Components/InstanceClient.cs b/src/Tgstation.Server.Client/Components/InstanceClient.cs index 70024af14b2..51a61aec1ed 100644 --- a/src/Tgstation.Server.Client/Components/InstanceClient.cs +++ b/src/Tgstation.Server.Client/Components/InstanceClient.cs @@ -11,7 +11,7 @@ sealed class InstanceClient : IInstanceClient public Instance Metadata { get; } /// - public IByondClient Byond { get; } + public IEngineClient Engine { get; } /// public IRepositoryClient Repository { get; } @@ -48,7 +48,7 @@ public InstanceClient(IApiClient apiClient, Instance instance) Metadata = instance ?? throw new ArgumentNullException(nameof(instance)); - Byond = new ByondClient(apiClient, instance); + Engine = new EngineClient(apiClient, instance); Repository = new RepositoryClient(apiClient, instance); DreamDaemon = new DreamDaemonClient(apiClient, instance); Configuration = new ConfigurationClient(apiClient, instance); diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/EngineController.cs similarity index 82% rename from src/Tgstation.Server.Host/Controllers/ByondController.cs rename to src/Tgstation.Server.Host/Controllers/EngineController.cs index b085f173922..83f69919917 100644 --- a/src/Tgstation.Server.Host/Controllers/ByondController.cs +++ b/src/Tgstation.Server.Host/Controllers/EngineController.cs @@ -24,18 +24,18 @@ namespace Tgstation.Server.Host.Controllers { /// - /// Controller for managing BYOND installations. + /// Controller for managing engine installations. /// - [Route(Routes.Byond)] - public sealed class ByondController : InstanceRequiredController + [Route(Routes.Engine)] + public sealed class EngineController : InstanceRequiredController { /// - /// The for the . + /// The for the . /// readonly IJobManager jobManager; /// - /// The for the . + /// The for the . /// readonly IFileTransferTicketProvider fileTransferService; @@ -47,7 +47,7 @@ public sealed class ByondController : InstanceRequiredController static Version NormalizeByondVersion(Version version) => version.Build == 0 ? new Version(version.Major, version.Minor) : version; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The for the . /// The for the . @@ -55,10 +55,10 @@ public sealed class ByondController : InstanceRequiredController /// The for the . /// The value of . /// The value of . - public ByondController( + public EngineController( IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, - ILogger logger, + ILogger logger, IInstanceManager instanceManager, IJobManager jobManager, IFileTransferTicketProvider fileTransferService) @@ -77,16 +77,16 @@ public ByondController( /// /// A resulting in the for the operation. /// Retrieved version information successfully. - /// No BYOND versions installed. + /// No engine versions installed. [HttpGet] - [TgsAuthorize(ByondRights.ReadActive)] - [ProducesResponseType(typeof(ByondResponse), 200)] + [TgsAuthorize(EngineRights.ReadActive)] + [ProducesResponseType(typeof(EngineResponse), 200)] [ProducesResponseType(typeof(ErrorMessageResponse), 409)] public ValueTask Read() => WithComponentInstance(instance => ValueTask.FromResult( Json( - new ByondResponse + new EngineResponse { EngineVersion = instance.EngineManager.ActiveVersion, }))); @@ -100,17 +100,17 @@ public ValueTask Read() /// A resulting in the for the operation. /// Retrieved version information successfully. [HttpGet(Routes.List)] - [TgsAuthorize(ByondRights.ListInstalled)] - [ProducesResponseType(typeof(PaginatedResponse), 200)] + [TgsAuthorize(EngineRights.ListInstalled)] + [ProducesResponseType(typeof(PaginatedResponse), 200)] public ValueTask List([FromQuery] int? page, [FromQuery] int? pageSize, CancellationToken cancellationToken) => WithComponentInstance( instance => Paginated( () => ValueTask.FromResult( - new PaginatableResult( + new PaginatableResult( instance .EngineManager .InstalledVersions - .Select(x => new ByondResponse + .Select(x => new EngineResponse { EngineVersion = x, }) @@ -122,24 +122,24 @@ public ValueTask List([FromQuery] int? page, [FromQuery] int? pag cancellationToken)); /// - /// Changes the active BYOND version to the one specified in a given . + /// Changes the active engine version to the one specified in a given . /// - /// The containing the to switch to. + /// The containing the to switch to. /// The for the operation. /// A resulting in the for the operation. - /// Switched active version successfully. - /// Created to install and switch active version successfully. + /// Switched active engine version successfully. + /// Created to install and switch active engine version successfully. [HttpPost] [TgsAuthorize( - ByondRights.InstallOfficialOrChangeActiveByondVersion - | ByondRights.InstallCustomByondVersion - | ByondRights.InstallOfficialOrChangeActiveOpenDreamVersion - | ByondRights.InstallCustomOpenDreamVersion)] - [ProducesResponseType(typeof(ByondInstallResponse), 200)] - [ProducesResponseType(typeof(ByondInstallResponse), 202)] + EngineRights.InstallOfficialOrChangeActiveByondVersion + | EngineRights.InstallCustomByondVersion + | EngineRights.InstallOfficialOrChangeActiveOpenDreamVersion + | EngineRights.InstallCustomOpenDreamVersion)] + [ProducesResponseType(typeof(EngineInstallResponse), 200)] + [ProducesResponseType(typeof(EngineInstallResponse), 202)] #pragma warning disable CA1502 // TODO: Decomplexify #pragma warning disable CA1506 - public async ValueTask Update([FromBody] ByondVersionRequest model, CancellationToken cancellationToken) + public async ValueTask Update([FromBody] EngineVersionRequest model, CancellationToken cancellationToken) #pragma warning restore CA1506 #pragma warning restore CA1502 { @@ -150,13 +150,13 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode var uploadingZip = model.UploadCustomZip == true; - var userByondRights = AuthenticationContext.InstancePermissionSet.ByondRights.Value; - if ((!userByondRights.HasFlag(ByondRights.InstallOfficialOrChangeActiveByondVersion) && !uploadingZip) - || (!userByondRights.HasFlag(ByondRights.InstallCustomByondVersion) && uploadingZip)) + var userByondRights = AuthenticationContext.InstancePermissionSet.EngineRights.Value; + if ((!userByondRights.HasFlag(EngineRights.InstallOfficialOrChangeActiveByondVersion) && !uploadingZip) + || (!userByondRights.HasFlag(EngineRights.InstallCustomByondVersion) && uploadingZip)) return Forbid(); // remove cruff fields - var result = new ByondInstallResponse(); + var result = new EngineInstallResponse(); return await WithComponentInstance( async instance => { @@ -200,8 +200,8 @@ public async ValueTask Update([FromBody] ByondVersionRequest mode { Description = $"Install {(!uploadingZip ? String.Empty : "custom ")}{model.EngineVersion.Engine.Value} version {model.EngineVersion.Version}", StartedBy = AuthenticationContext.User, - CancelRightsType = RightsType.Byond, - CancelRight = (ulong)ByondRights.CancelInstall, + CancelRightsType = RightsType.Engine, + CancelRight = (ulong)EngineRights.CancelInstall, Instance = Instance, }; @@ -261,18 +261,18 @@ await core.EngineManager.ChangeVersion( /// /// Attempts to delete the BYOND version specified in a given from the instance. /// - /// The containing the to delete. + /// The containing the to delete. /// The for the operation. /// A resulting in the for the operation. /// Created to delete target version successfully. /// Attempted to delete the active BYOND . /// The specified was not installed. [HttpDelete] - [TgsAuthorize(ByondRights.DeleteInstall)] + [TgsAuthorize(EngineRights.DeleteInstall)] [ProducesResponseType(typeof(JobResponse), 202)] [ProducesResponseType(typeof(ErrorMessageResponse), 409)] [ProducesResponseType(typeof(ErrorMessageResponse), 410)] - public async ValueTask Delete([FromBody] ByondVersionDeleteRequest model, CancellationToken cancellationToken) + public async ValueTask Delete([FromBody] EngineVersionDeleteRequest model, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(model); var earlyOut = ValidateEngineVersion(model.EngineVersion); @@ -306,13 +306,13 @@ public async ValueTask Delete([FromBody] ByondVersionDeleteReques { Description = $"Delete installed engine version {model}", StartedBy = AuthenticationContext.User, - CancelRightsType = RightsType.Byond, + CancelRightsType = RightsType.Engine, CancelRight = (ulong)( isByondVersion ? model.EngineVersion.Version.Build != -1 - ? ByondRights.InstallOfficialOrChangeActiveByondVersion - : ByondRights.InstallCustomByondVersion - : ByondRights.InstallCustomOpenDreamVersion | ByondRights.InstallOfficialOrChangeActiveOpenDreamVersion), + ? EngineRights.InstallOfficialOrChangeActiveByondVersion + : EngineRights.InstallCustomByondVersion + : EngineRights.InstallCustomOpenDreamVersion | EngineRights.InstallOfficialOrChangeActiveOpenDreamVersion), Instance = Instance, }; diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index 0e2ebf234e6..494b27db2bf 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -532,7 +532,7 @@ public async ValueTask List( query = query .Where(x => x.InstancePermissionSets.Any(y => y.PermissionSetId == AuthenticationContext.PermissionSet.Id.Value)) .Where(x => x.InstancePermissionSets.Any(instanceUser => - instanceUser.ByondRights != ByondRights.None || + instanceUser.EngineRights != EngineRights.None || instanceUser.ChatBotRights != ChatBotRights.None || instanceUser.ConfigurationRights != ConfigurationRights.None || instanceUser.DreamDaemonRights != DreamDaemonRights.None || @@ -609,7 +609,7 @@ public async ValueTask GetId(long id, CancellationToken cancellat if (cantList && !instance.InstancePermissionSets.Any(instanceUser => instanceUser.PermissionSetId == AuthenticationContext.PermissionSet.Id.Value && (instanceUser.RepositoryRights != RepositoryRights.None || - instanceUser.ByondRights != ByondRights.None || + instanceUser.EngineRights != EngineRights.None || instanceUser.ChatBotRights != ChatBotRights.None || instanceUser.ConfigurationRights != ConfigurationRights.None || instanceUser.DreamDaemonRights != DreamDaemonRights.None || @@ -765,7 +765,7 @@ InstancePermissionSet InstanceAdminPermissionSet(InstancePermissionSet permissio { PermissionSetId = AuthenticationContext.PermissionSet.Id.Value, }; - permissionSetToModify.ByondRights = RightsHelper.AllRights(); + permissionSetToModify.EngineRights = RightsHelper.AllRights(); permissionSetToModify.ChatBotRights = RightsHelper.AllRights(); permissionSetToModify.ConfigurationRights = RightsHelper.AllRights(); permissionSetToModify.DreamDaemonRights = RightsHelper.AllRights(); diff --git a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs index ca8fdae67bb..381cae1bc7d 100644 --- a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs @@ -93,7 +93,7 @@ public async ValueTask Create([FromBody] InstancePermissionSetReq var dbUser = new InstancePermissionSet { - ByondRights = RightsHelper.Clamp(model.ByondRights ?? ByondRights.None), + EngineRights = RightsHelper.Clamp(model.EngineRights ?? EngineRights.None), ChatBotRights = RightsHelper.Clamp(model.ChatBotRights ?? ChatBotRights.None), ConfigurationRights = RightsHelper.Clamp(model.ConfigurationRights ?? ConfigurationRights.None), DreamDaemonRights = RightsHelper.Clamp(model.DreamDaemonRights ?? DreamDaemonRights.None), @@ -138,7 +138,7 @@ public async ValueTask Update([FromBody] InstancePermissionSetReq if (originalPermissionSet == null) return this.Gone(); - originalPermissionSet.ByondRights = RightsHelper.Clamp(model.ByondRights ?? originalPermissionSet.ByondRights.Value); + originalPermissionSet.EngineRights = RightsHelper.Clamp(model.EngineRights ?? originalPermissionSet.EngineRights.Value); originalPermissionSet.RepositoryRights = RightsHelper.Clamp(model.RepositoryRights ?? originalPermissionSet.RepositoryRights.Value); originalPermissionSet.InstancePermissionSetRights = RightsHelper.Clamp(model.InstancePermissionSetRights ?? originalPermissionSet.InstancePermissionSetRights.Value); originalPermissionSet.ChatBotRights = RightsHelper.Clamp(model.ChatBotRights ?? originalPermissionSet.ChatBotRights.Value); diff --git a/src/Tgstation.Server.Host/Controllers/TgsAuthorizeAttribute.cs b/src/Tgstation.Server.Host/Controllers/TgsAuthorizeAttribute.cs index a16cf7646dd..f9059358e41 100644 --- a/src/Tgstation.Server.Host/Controllers/TgsAuthorizeAttribute.cs +++ b/src/Tgstation.Server.Host/Controllers/TgsAuthorizeAttribute.cs @@ -58,11 +58,11 @@ public TgsAuthorizeAttribute(RepositoryRights requiredRights) /// /// Initializes a new instance of the class. /// - /// The required. - public TgsAuthorizeAttribute(ByondRights requiredRights) + /// The required. + public TgsAuthorizeAttribute(EngineRights requiredRights) { Roles = RightsHelper.RoleNames(requiredRights); - RightsType = Api.Rights.RightsType.Byond; + RightsType = Api.Rights.RightsType.Engine; } /// diff --git a/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs b/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs index 00509126f0d..623e920734b 100644 --- a/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs +++ b/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs @@ -32,7 +32,7 @@ public sealed class InstancePermissionSet : Api.Models.Internal.InstancePermissi /// public InstancePermissionSetResponse ToApi() => new InstancePermissionSetResponse { - ByondRights = ByondRights, + EngineRights = EngineRights, ChatBotRights = ChatBotRights, ConfigurationRights = ConfigurationRights, DreamDaemonRights = DreamDaemonRights, diff --git a/tests/Tgstation.Server.Api.Tests/Rights/TestRights.cs b/tests/Tgstation.Server.Api.Tests/Rights/TestRights.cs index 7589120c61d..d96216968b7 100644 --- a/tests/Tgstation.Server.Api.Tests/Rights/TestRights.cs +++ b/tests/Tgstation.Server.Api.Tests/Rights/TestRights.cs @@ -40,10 +40,10 @@ public void TestAllPowerOfTwo() [TestMethod] public void TestAllRightsWorks() { - var allByondRights = ByondRights.CancelInstall | ByondRights.InstallOfficialOrChangeActiveByondVersion | ByondRights.ListInstalled | ByondRights.ReadActive | ByondRights.InstallCustomByondVersion | ByondRights.DeleteInstall | ByondRights.InstallCustomOpenDreamVersion | ByondRights.InstallOfficialOrChangeActiveOpenDreamVersion; - var automaticByondRights = RightsHelper.AllRights(); + var allEngineRights = EngineRights.CancelInstall | EngineRights.InstallOfficialOrChangeActiveByondVersion | EngineRights.ListInstalled | EngineRights.ReadActive | EngineRights.InstallCustomByondVersion | EngineRights.DeleteInstall | EngineRights.InstallCustomOpenDreamVersion | EngineRights.InstallOfficialOrChangeActiveOpenDreamVersion; + var automaticByondRights = RightsHelper.AllRights(); - Assert.AreEqual(allByondRights, automaticByondRights); + Assert.AreEqual(allEngineRights, automaticByondRights); } } } diff --git a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs index 941d254133f..cfbd9be15e9 100644 --- a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs +++ b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs @@ -24,7 +24,7 @@ public sealed class TestApiClient [TestMethod] public async Task TestDeserializingByondModelsWork() { - var sample = new ByondResponse + var sample = new EngineResponse { EngineVersion = new EngineVersion { @@ -49,7 +49,7 @@ public async Task TestDeserializingByondModelsWork() var client = new ApiClient(httpClient.Object, new Uri("http://fake.com"), new ApiHeaders(new ProductHeaderValue("fake"), "fake"), null, false); - var result = await client.Read(Routes.Byond, default); + var result = await client.Read(Routes.Engine, default); Assert.AreEqual(sample.EngineVersion, result.EngineVersion); Assert.AreEqual(-1, result.EngineVersion.Version.Build); Assert.IsFalse(result.EngineVersion.CustomIteration.HasValue); @@ -58,7 +58,7 @@ public async Task TestDeserializingByondModelsWork() [TestMethod] public async Task TestUnrecognizedResponse() { - var sample = new ByondResponse + var sample = new EngineResponse { EngineVersion = new EngineVersion { @@ -79,7 +79,7 @@ public async Task TestUnrecognizedResponse() var client = new ApiClient(httpClient.Object, new Uri("http://fake.com"), new ApiHeaders(new ProductHeaderValue("fake"), "fake"), null, true); - await Assert.ThrowsExceptionAsync(() => client.Read(Routes.Byond, default).AsTask()); + await Assert.ThrowsExceptionAsync(() => client.Read(Routes.Engine, default).AsTask()); } } } diff --git a/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs b/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs index fb0bea813d0..17a1f332115 100644 --- a/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs +++ b/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs @@ -50,9 +50,9 @@ public void TestGetRightsGeneric() var authContext = new AuthenticationContext(null, user, instanceUser); user.PermissionSet.AdministrationRights = AdministrationRights.WriteUsers; - instanceUser.ByondRights = ByondRights.InstallOfficialOrChangeActiveByondVersion | ByondRights.ReadActive; + instanceUser.EngineRights = EngineRights.InstallOfficialOrChangeActiveByondVersion | EngineRights.ReadActive; Assert.AreEqual((ulong)user.PermissionSet.AdministrationRights, authContext.GetRight(RightsType.Administration)); - Assert.AreEqual((ulong)instanceUser.ByondRights, authContext.GetRight(RightsType.Byond)); + Assert.AreEqual((ulong)instanceUser.EngineRights, authContext.GetRight(RightsType.Engine)); } } } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs index 0779707fd76..991281ac02a 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs @@ -26,9 +26,9 @@ namespace Tgstation.Server.Tests.Live.Instance { - sealed class ByondTest(IByondClient byondClient, IJobsClient jobsClient, IFileDownloader fileDownloader, Api.Models.Instance metadata, EngineType engineType) : JobsRequiredTest(jobsClient) + sealed class ByondTest(IEngineClient byondClient, IJobsClient jobsClient, IFileDownloader fileDownloader, Api.Models.Instance metadata, EngineType engineType) : JobsRequiredTest(jobsClient) { - readonly IByondClient byondClient = byondClient ?? throw new ArgumentNullException(nameof(byondClient)); + readonly IEngineClient byondClient = byondClient ?? throw new ArgumentNullException(nameof(byondClient)); readonly IFileDownloader fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); readonly Api.Models.Instance metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); @@ -110,9 +110,9 @@ async Task RunPartOne(CancellationToken cancellationToken) } ValueTask TestInstallNullVersion(CancellationToken cancellationToken) - => ApiAssert.ThrowsException( + => ApiAssert.ThrowsException( () => byondClient.SetActiveVersion( - new ByondVersionRequest + new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -133,7 +133,7 @@ async Task RunContinued(Task firstInstall, CancellationToken cancellationToken) async Task TestDeletes(CancellationToken cancellationToken) { - var deleteThisOneBecauseItWasntPartOfTheOriginalTest = await byondClient.DeleteVersion(new ByondVersionDeleteRequest + var deleteThisOneBecauseItWasntPartOfTheOriginalTest = await byondClient.DeleteVersion(new EngineVersionDeleteRequest { EngineVersion = new EngineVersion { @@ -145,7 +145,7 @@ async Task TestDeletes(CancellationToken cancellationToken) await WaitForJob(deleteThisOneBecauseItWasntPartOfTheOriginalTest, 30, false, null, cancellationToken); var nonExistentUninstallResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( - new ByondVersionDeleteRequest + new EngineVersionDeleteRequest { EngineVersion = new EngineVersion { @@ -156,7 +156,7 @@ async Task TestDeletes(CancellationToken cancellationToken) cancellationToken), ErrorCode.ResourceNotPresent); var uninstallResponseTask = byondClient.DeleteVersion( - new ByondVersionDeleteRequest + new EngineVersionDeleteRequest { EngineVersion = new EngineVersion { @@ -168,7 +168,7 @@ async Task TestDeletes(CancellationToken cancellationToken) cancellationToken); var badBecauseActiveResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( - new ByondVersionDeleteRequest + new EngineVersionDeleteRequest { EngineVersion = new EngineVersion { @@ -203,7 +203,7 @@ async Task TestDeletes(CancellationToken cancellationToken) async Task TestInstallFakeVersion(CancellationToken cancellationToken) { - var newModel = new ByondVersionRequest + var newModel = new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -211,7 +211,7 @@ async Task TestInstallFakeVersion(CancellationToken cancellationToken) } }; - await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(newModel, null, cancellationToken), ErrorCode.ModelValidationFailure); + await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(newModel, null, cancellationToken), ErrorCode.ModelValidationFailure); newModel.EngineVersion.Engine = testEngine; @@ -222,7 +222,7 @@ async Task TestInstallFakeVersion(CancellationToken cancellationToken) async Task TestInstallStable(CancellationToken cancellationToken) { - var newModel = new ByondVersionRequest + var newModel = new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -290,7 +290,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) await using var stableBytesMs = await TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(testVersion, null, cancellationToken), cancellationToken); var test = await byondClient.SetActiveVersion( - new ByondVersionRequest + new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -309,7 +309,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) // do it again. #1501 stableBytesMs.Seek(0, SeekOrigin.Begin); var test2 = await byondClient.SetActiveVersion( - new ByondVersionRequest + new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -331,7 +331,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) Assert.AreEqual(2, newSettings.EngineVersion.CustomIteration); // test a few switches - var installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest + var installResponse = await byondClient.SetActiveVersion(new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -341,7 +341,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) } }, null, cancellationToken); Assert.IsNull(installResponse.InstallJob); - await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(new ByondVersionRequest + await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -351,7 +351,7 @@ await ApiAssert.ThrowsException(() = } }, null, cancellationToken), ErrorCode.EngineNonExistentCustomVersion); - installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest + installResponse = await byondClient.SetActiveVersion(new EngineVersionRequest { EngineVersion = new EngineVersion { diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 0a8486713d4..c50f4d25673 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -43,7 +43,7 @@ public async Task RunTests( CancellationToken cancellationToken) { var testVersion = await ByondTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); - var byondTest = new ByondTest(instanceClient.Byond, instanceClient.Jobs, fileDownloader, instanceClient.Metadata, testVersion.Engine.Value); + var byondTest = new ByondTest(instanceClient.Engine, instanceClient.Jobs, fileDownloader, instanceClient.Metadata, testVersion.Engine.Value); var chatTest = new ChatTest(instanceClient.ChatBots, instanceManagerClient, instanceClient.Jobs, instanceClient.Metadata); var configTest = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata); var repoTest = new RepositoryTest(instanceClient.Repository, instanceClient.Jobs); @@ -171,10 +171,10 @@ public async Task RunCompatTests( using var windowsByondInstaller = byondInstaller as WindowsByondInstaller; // get the bytes for stable - ByondInstallResponse installJob2; + EngineInstallResponse installJob2; await using (var stableBytesMs = await TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(compatVersion, null, cancellationToken), cancellationToken)) { - installJob2 = await instanceClient.Byond.SetActiveVersion(new ByondVersionRequest + installJob2 = await instanceClient.Engine.SetActiveVersion(new EngineVersionRequest { UploadCustomZip = true, EngineVersion = new EngineVersion @@ -202,7 +202,7 @@ await Task.WhenAll( if (compatVersion.Engine.Value == EngineType.OpenDream) { Assert.IsNotNull(compatVersion.SourceSHA); - var activeVersion = await instanceClient.Byond.ActiveVersion(cancellationToken); + var activeVersion = await instanceClient.Engine.ActiveVersion(cancellationToken); Assert.AreEqual(Limits.MaximumCommitShaLength, activeVersion.EngineVersion.SourceSHA.Length); Assert.AreEqual(compatVersion.SourceSHA, activeVersion.EngineVersion.SourceSHA); Assert.AreEqual(compatVersion.Version, activeVersion.EngineVersion.Version); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index e9cf08e996e..ba69db8069b 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -89,7 +89,7 @@ public async Task Run(CancellationToken cancellationToken) async Task CheckByondVersions() { - var listTask = instanceClient.Byond.InstalledVersions(null, cancellationToken); + var listTask = instanceClient.Engine.InstalledVersions(null, cancellationToken); var list = await listTask; @@ -251,13 +251,13 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationToken cancellationToken) { - var currentByond = await instanceClient.Byond.ActiveVersion(cancellationToken); + var currentByond = await instanceClient.Engine.ActiveVersion(cancellationToken); Assert.IsNotNull(currentByond); Assert.AreEqual(testVersion, currentByond.EngineVersion); // Change the active version and check we get delayed while deleting the old one because the watchdog is using it - var setActiveResponse = await instanceClient.Byond.SetActiveVersion( - new ByondVersionRequest + var setActiveResponse = await instanceClient.Engine.SetActiveVersion( + new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -273,8 +273,8 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo Assert.IsNotNull(setActiveResponse); Assert.IsNull(setActiveResponse.InstallJob); - var deleteJob = await instanceClient.Byond.DeleteVersion( - new ByondVersionDeleteRequest + var deleteJob = await instanceClient.Engine.DeleteVersion( + new EngineVersionDeleteRequest { EngineVersion = new EngineVersion { @@ -293,8 +293,8 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo Assert.IsTrue(deleteJob.Stage.Contains("Waiting")); // then change it back and check it fails the job because it's active again - setActiveResponse = await instanceClient.Byond.SetActiveVersion( - new ByondVersionRequest + setActiveResponse = await instanceClient.Engine.SetActiveVersion( + new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -313,8 +313,8 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo // finally, queue the last delete job which should complete when the watchdog restarts with a newly deployed .dmb // queue the byond change followed by the deployment for that first - setActiveResponse = await instanceClient.Byond.SetActiveVersion( - new ByondVersionRequest + setActiveResponse = await instanceClient.Engine.SetActiveVersion( + new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -330,8 +330,8 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo Assert.IsNotNull(setActiveResponse); Assert.IsNull(setActiveResponse.InstallJob); - deleteJob = await instanceClient.Byond.DeleteVersion( - new ByondVersionDeleteRequest + deleteJob = await instanceClient.Engine.DeleteVersion( + new EngineVersionDeleteRequest { EngineVersion = new EngineVersion { @@ -1015,7 +1015,7 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken System.Console.WriteLine("TEST: WATCHDOG BYOND VERSION UPDATE TEST"); var versionToInstall = testVersion; - var currentByondVersion = await instanceClient.Byond.ActiveVersion(cancellationToken); + var currentByondVersion = await instanceClient.Engine.ActiveVersion(cancellationToken); Assert.AreNotEqual(versionToInstall, currentByondVersion.EngineVersion); var initialStatus = await instanceClient.DreamDaemon.Read(cancellationToken); @@ -1026,8 +1026,8 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken CheckDDPriority(); - var byondInstallJobTask = instanceClient.Byond.SetActiveVersion( - new ByondVersionRequest + var byondInstallJobTask = instanceClient.Engine.SetActiveVersion( + new EngineVersionRequest { EngineVersion = new EngineVersion { diff --git a/tests/Tgstation.Server.Tests/TestDatabase.cs b/tests/Tgstation.Server.Tests/TestDatabase.cs index 8d629bcfb67..320c4e32b80 100644 --- a/tests/Tgstation.Server.Tests/TestDatabase.cs +++ b/tests/Tgstation.Server.Tests/TestDatabase.cs @@ -134,7 +134,7 @@ DatabaseContext CreateContext() { new Host.Models.InstancePermissionSet { - ByondRights = ByondRights.InstallCustomByondVersion, + EngineRights = EngineRights.InstallCustomByondVersion, ChatBotRights = ChatBotRights.None, ConfigurationRights = ConfigurationRights.Read, DreamDaemonRights = DreamDaemonRights.ReadRevision, diff --git a/tools/Tgstation.Server.Migrator.Comms/Program.cs b/tools/Tgstation.Server.Migrator.Comms/Program.cs index 91ad70de97c..326de7cf934 100644 --- a/tools/Tgstation.Server.Migrator.Comms/Program.cs +++ b/tools/Tgstation.Server.Migrator.Comms/Program.cs @@ -223,12 +223,12 @@ static async Task Migrate(IClient tgs3Client, ushort apiPort) var byondDirectory = Path.Combine(instancePath, "BYOND"); var byondVersionFile = Path.Combine(byondDirectory, "byond_version.dat"); - ByondVersionRequest? byondVersionRequest = null; + 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 ByondVersionRequest + byondVersionRequest = new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -331,7 +331,7 @@ static async Task Migrate(IClient tgs3Client, ushort apiPort) if (byondVersionRequest != null) { Console.WriteLine("Triggering BYOND install job..."); - await v5InstanceClient.Byond.SetActiveVersion(byondVersionRequest, null, default); + await v5InstanceClient.Engine.SetActiveVersion(byondVersionRequest, null, default); } if (repositoryUpdateRequest != null) From 8e5f2dd6960da28ef92cb2e36b410688a815c792 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 02:45:48 -0400 Subject: [PATCH 110/717] Undo breaking API 10 changes - Restore backwards compatible `ByondController` --- build/Version.props | 2 +- .../Models/Internal/InstancePermissionSet.cs | 11 +- .../Controllers/Legacy/ByondController.cs | 345 ++++++++++++++++++ .../Legacy/Models/ByondInstallResponse.cs | 27 ++ .../Legacy/Models/ByondResponse.cs | 18 + .../Models/ByondVersionDeleteRequest.cs | 18 + .../Legacy/Models/ByondVersionRequest.cs | 23 ++ .../CachingFileDownloader.cs | 2 +- .../Instance/{ByondTest.cs => EngineTest.cs} | 40 +- .../Live/Instance/InstanceTest.cs | 23 +- .../Live/Instance/LegacyByondClient.cs | 67 ++++ .../Live/Instance/LegacyByondTest.cs | 240 ++++++++++++ .../Live/TestLiveServer.cs | 16 +- 13 files changed, 804 insertions(+), 28 deletions(-) create mode 100644 src/Tgstation.Server.Host/Controllers/Legacy/ByondController.cs create mode 100644 src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondInstallResponse.cs create mode 100644 src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondResponse.cs create mode 100644 src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionDeleteRequest.cs create mode 100644 src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionRequest.cs rename tests/Tgstation.Server.Tests/Live/Instance/{ByondTest.cs => EngineTest.cs} (87%) create mode 100644 tests/Tgstation.Server.Tests/Live/Instance/LegacyByondClient.cs create mode 100644 tests/Tgstation.Server.Tests/Live/Instance/LegacyByondTest.cs diff --git a/build/Version.props b/build/Version.props index 05c5365352d..31e62df8db4 100644 --- a/build/Version.props +++ b/build/Version.props @@ -5,7 +5,7 @@ 6.0.0 5.0.0 - 10.0.0 + 9.13.0 6.0.1 12.0.0 13.0.0 diff --git a/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs b/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs index 1564e5949a0..94ec3c5246e 100644 --- a/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs +++ b/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs @@ -2,6 +2,8 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Newtonsoft.Json; + using Tgstation.Server.Api.Rights; namespace Tgstation.Server.Api.Models.Internal @@ -27,7 +29,14 @@ public abstract class InstancePermissionSet /// The of the . /// [NotMapped] - public EngineRights? EngineRights { get; set; } + [JsonIgnore] + public EngineRights? EngineRights + { +#pragma warning disable CS0618 // Type or member is obsolete + get => ByondRights; + set => ByondRights = value; +#pragma warning restore CS0618 // Type or member is obsolete + } /// /// The legacy of the . diff --git a/src/Tgstation.Server.Host/Controllers/Legacy/ByondController.cs b/src/Tgstation.Server.Host/Controllers/Legacy/ByondController.cs new file mode 100644 index 00000000000..2ca7bafb47e --- /dev/null +++ b/src/Tgstation.Server.Host/Controllers/Legacy/ByondController.cs @@ -0,0 +1,345 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +using Tgstation.Server.Api; +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Api.Models.Response; +using Tgstation.Server.Api.Rights; +using Tgstation.Server.Host.Components; +using Tgstation.Server.Host.Controllers.Legacy.Models; +using Tgstation.Server.Host.Database; +using Tgstation.Server.Host.Extensions; +using Tgstation.Server.Host.Jobs; +using Tgstation.Server.Host.Models; +using Tgstation.Server.Host.Security; +using Tgstation.Server.Host.Transfer; + +namespace Tgstation.Server.Host.Controllers.Legacy +{ + /// + /// Controller for managing BYOND installations. + /// + [Route(Routes.Root + "Byond")] + public sealed class ByondController : InstanceRequiredController + { + /// + /// The for the . + /// + readonly IJobManager jobManager; + + /// + /// The for the . + /// + readonly IFileTransferTicketProvider fileTransferService; + + /// + /// Create an for a given legacy formatted BYOND . + /// + /// The legacy BYOND . + /// A . + static EngineVersion CreateEngineVersionFromLegacyByondVersion(Version version) => new EngineVersion + { + Version = new Version(version.Major, version.Minor), + Engine = EngineType.Byond, + CustomIteration = version.Build <= 0 ? null : version.Build, + }; + + /// + /// Create a legacy formated BYOND for a given . + /// + /// The . + /// A legacy BYOND . + static Version CreateLegacyByondVersionFromEngineVersion(EngineVersion engineVersion) + => new (engineVersion.Version.Major, engineVersion.Version.Minor, engineVersion.CustomIteration ?? 0); + + /// + /// Initializes a new instance of the class. + /// + /// The for the . + /// The for the . + /// The for the . + /// The for the . + /// The value of . + /// The value of . + public ByondController( + IDatabaseContext databaseContext, + IAuthenticationContextFactory authenticationContextFactory, + ILogger logger, + IInstanceManager instanceManager, + IJobManager jobManager, + IFileTransferTicketProvider fileTransferService) + : base( + databaseContext, + authenticationContextFactory, + logger, + instanceManager) + { + this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); + this.fileTransferService = fileTransferService ?? throw new ArgumentNullException(nameof(fileTransferService)); + } + + /// + /// Gets the active . + /// + /// A resulting in the for the operation. + /// Retrieved version information successfully. + [HttpGet] + [TgsAuthorize(EngineRights.ReadActive)] + [ProducesResponseType(typeof(ByondResponse), 200)] + public ValueTask Read() + => WithComponentInstance(instance => + { + var version = instance.EngineManager.ActiveVersion; + return ValueTask.FromResult( + Json(new ByondResponse + { + Version = version?.Engine.Value == EngineType.Byond + ? CreateLegacyByondVersionFromEngineVersion(version) + : null, + })); + }); + + /// + /// Lists installed s. + /// + /// The current page. + /// The page size. + /// The for the operation. + /// A resulting in the for the operation. + /// Retrieved version information successfully. + [HttpGet(Routes.List)] + [TgsAuthorize(EngineRights.ListInstalled)] + [ProducesResponseType(typeof(PaginatedResponse), 200)] + public ValueTask List([FromQuery] int? page, [FromQuery] int? pageSize, CancellationToken cancellationToken) + => WithComponentInstance( + instance => Paginated( + () => ValueTask.FromResult( + new PaginatableResult( + instance + .EngineManager + .InstalledVersions + .Where(x => x.Engine.Value == EngineType.Byond) + .Select(x => new ByondResponse + { + Version = CreateLegacyByondVersionFromEngineVersion(x), + }) + .AsQueryable() + .OrderBy(x => x.Version))), + null, + page, + pageSize, + cancellationToken)); + + /// + /// Changes the active BYOND version to the one specified in a given . + /// + /// The containing the to switch to. + /// The for the operation. + /// A resulting in the for the operation. + /// Switched active version successfully. + /// Created to install and switch active version successfully. + [HttpPost] + [TgsAuthorize(EngineRights.InstallOfficialOrChangeActiveByondVersion | EngineRights.InstallCustomByondVersion)] + [ProducesResponseType(typeof(ByondInstallResponse), 200)] + [ProducesResponseType(typeof(ByondInstallResponse), 202)] +#pragma warning disable CA1506 // TODO: Decomplexify + public async ValueTask Update([FromBody] ByondVersionRequest model, CancellationToken cancellationToken) +#pragma warning restore CA1506 + { + ArgumentNullException.ThrowIfNull(model); + + var uploadingZip = model.UploadCustomZip == true; + + if (model.Version == null + || model.Version.Revision != -1 + || (uploadingZip && model.Version.Build > 0)) + return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); + + var userEngineRights = AuthenticationContext.InstancePermissionSet.EngineRights.Value; + if ((!userEngineRights.HasFlag(EngineRights.InstallOfficialOrChangeActiveByondVersion) && !uploadingZip) + || (!userEngineRights.HasFlag(EngineRights.InstallCustomByondVersion) && uploadingZip)) + return Forbid(); + + // remove cruff fields + var result = new ByondInstallResponse(); + return await WithComponentInstance( + async instance => + { + var byondManager = instance.EngineManager; + var engineVersion = CreateEngineVersionFromLegacyByondVersion(model.Version); + var versionAlreadyInstalled = !uploadingZip + && byondManager + .InstalledVersions + .Any(x => x.Equals(engineVersion)); + if (versionAlreadyInstalled) + { + Logger.LogInformation( + "User ID {userId} changing instance ID {instanceId} BYOND version to {newByondVersion}", + AuthenticationContext.User.Id, + Instance.Id, + engineVersion); + + try + { + await byondManager.ChangeVersion( + null, + engineVersion, + null, + false, + cancellationToken); + } + catch (InvalidOperationException ex) + { + Logger.LogDebug( + ex, + "Race condition: BYOND version {version} uninstalled before we could switch to it. Creating install job instead...", + engineVersion); + versionAlreadyInstalled = false; + } + } + + if (!versionAlreadyInstalled) + { + if (engineVersion.CustomIteration.HasValue) + return BadRequest(new ErrorMessageResponse(ErrorCode.EngineNonExistentCustomVersion)); + + Logger.LogInformation( + "User ID {userId} installing BYOND version to {newByondVersion} on instance ID {instanceId}", + AuthenticationContext.User.Id, + engineVersion, + Instance.Id); + + // run the install through the job manager + var job = new Host.Models.Job + { + Description = $"Install {(!uploadingZip ? string.Empty : "custom ")}BYOND version {engineVersion}", + StartedBy = AuthenticationContext.User, + CancelRightsType = RightsType.Engine, + CancelRight = (ulong)EngineRights.CancelInstall, + Instance = Instance, + }; + + IFileUploadTicket fileUploadTicket = null; + if (uploadingZip) + fileUploadTicket = fileTransferService.CreateUpload(FileUploadStreamKind.None); + + try + { + await jobManager.RegisterOperation( + job, + async (core, databaseContextFactory, paramJob, progressHandler, jobCancellationToken) => + { + Stream zipFileStream = null; + if (fileUploadTicket != null) + await using (fileUploadTicket) + { + var uploadStream = await fileUploadTicket.GetResult(jobCancellationToken) ?? throw new JobException(ErrorCode.FileUploadExpired); + zipFileStream = new MemoryStream(); + try + { + await uploadStream.CopyToAsync(zipFileStream, jobCancellationToken); + } + catch + { + await zipFileStream.DisposeAsync(); + throw; + } + } + + await using (zipFileStream) + await core.EngineManager.ChangeVersion( + progressHandler, + engineVersion, + zipFileStream, + true, + jobCancellationToken); + }, + cancellationToken); + + result.InstallJob = job.ToApi(); + result.FileTicket = fileUploadTicket?.Ticket.FileTicket; + } + catch + { + if (fileUploadTicket != null) + await fileUploadTicket.DisposeAsync(); + + throw; + } + } + + return result.InstallJob != null ? Accepted(result) : Json(result); + }); + } + + /// + /// Attempts to delete the BYOND version specified in a given from the instance. + /// + /// The containing the to delete. + /// The for the operation. + /// A resulting in the for the operation. + /// Created to delete target version successfully. + /// Attempted to delete the active BYOND . + /// The specified was not installed. + [HttpDelete] + [TgsAuthorize(EngineRights.DeleteInstall)] + [ProducesResponseType(typeof(JobResponse), 202)] + [ProducesResponseType(typeof(ErrorMessageResponse), 409)] + [ProducesResponseType(typeof(ErrorMessageResponse), 410)] + public async ValueTask Delete([FromBody] ByondVersionDeleteRequest model, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(model); + + if (model.Version == null + || model.Version.Revision != -1) + return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); + + var engineVersion = CreateEngineVersionFromLegacyByondVersion(model.Version); + var notInstalledResponse = await WithComponentInstance( + instance => + { + var engineManager = instance.EngineManager; + + if (engineVersion.Equals(engineManager.ActiveVersion)) + return ValueTask.FromResult( + Conflict(new ErrorMessageResponse(ErrorCode.EngineCannotDeleteActiveVersion))); + + var versionNotInstalled = !engineManager.InstalledVersions.Any(x => x.Equals(engineVersion)); + + return ValueTask.FromResult( + versionNotInstalled + ? this.Gone() + : null); + }); + + if (notInstalledResponse != null) + return notInstalledResponse; + + // run the install through the job manager + var job = new Host.Models.Job + { + Description = $"Delete installed BYOND version {engineVersion}", + StartedBy = AuthenticationContext.User, + CancelRightsType = RightsType.Engine, + CancelRight = (ulong)(engineVersion.CustomIteration.HasValue ? EngineRights.InstallOfficialOrChangeActiveByondVersion : EngineRights.InstallCustomByondVersion), + Instance = Instance, + }; + + await jobManager.RegisterOperation( + job, + (instanceCore, databaseContextFactory, job, progressReporter, jobCancellationToken) + => instanceCore.EngineManager.DeleteVersion(progressReporter, engineVersion, jobCancellationToken), + cancellationToken); + + var apiResponse = job.ToApi(); + return Accepted(apiResponse); + } + } +} diff --git a/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondInstallResponse.cs b/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondInstallResponse.cs new file mode 100644 index 00000000000..5cda990b2c9 --- /dev/null +++ b/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondInstallResponse.cs @@ -0,0 +1,27 @@ +using System; + +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Response; + +namespace Tgstation.Server.Host.Controllers.Legacy.Models +{ + /// + /// Represents a BYOND installation job. is used to upload custom BYOND version zip files. + /// + public sealed class ByondInstallResponse : FileTicketResponse + { + /// + /// The being used to install a new . + /// + [ResponseOptions] + public JobResponse InstallJob { get; set; } + + /// + [ResponseOptions] + public override string FileTicket + { + get => base.FileTicket; + set => base.FileTicket = value; + } + } +} diff --git a/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondResponse.cs b/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondResponse.cs new file mode 100644 index 00000000000..d541717e8d2 --- /dev/null +++ b/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondResponse.cs @@ -0,0 +1,18 @@ +using System; + +using Tgstation.Server.Api.Models; + +namespace Tgstation.Server.Host.Controllers.Legacy.Models +{ + /// + /// Represents an installed BYOND . + /// + public sealed class ByondResponse + { + /// + /// The installed BYOND . BYOND itself only considers the and numbers. This older API uses the number to represent installed custom versions. + /// + [ResponseOptions] + public Version Version { get; set; } + } +} diff --git a/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionDeleteRequest.cs b/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionDeleteRequest.cs new file mode 100644 index 00000000000..9293129298c --- /dev/null +++ b/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionDeleteRequest.cs @@ -0,0 +1,18 @@ +using System; + +using Tgstation.Server.Api.Models; + +namespace Tgstation.Server.Host.Controllers.Legacy.Models +{ + /// + /// A request to delete a specific . + /// + public class ByondVersionDeleteRequest + { + /// + /// The BYOND version to delete. + /// + [RequestOptions(FieldPresence.Required)] + public Version Version { get; set; } + } +} diff --git a/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionRequest.cs b/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionRequest.cs new file mode 100644 index 00000000000..59aebebacc7 --- /dev/null +++ b/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionRequest.cs @@ -0,0 +1,23 @@ +using System; + +using Tgstation.Server.Api.Models; + +namespace Tgstation.Server.Host.Controllers.Legacy.Models +{ + /// + /// A request to install a BYOND . + /// + public sealed class ByondVersionRequest + { + /// + /// The BYOND version to install. + /// + [RequestOptions(FieldPresence.Required)] + public Version Version { get; set; } + + /// + /// If a custom BYOND version is to be uploaded. + /// + public bool? UploadCustomZip { get; set; } + } +} diff --git a/tests/Tgstation.Server.Tests/CachingFileDownloader.cs b/tests/Tgstation.Server.Tests/CachingFileDownloader.cs index 4b66154d438..680307cd234 100644 --- a/tests/Tgstation.Server.Tests/CachingFileDownloader.cs +++ b/tests/Tgstation.Server.Tests/CachingFileDownloader.cs @@ -43,7 +43,7 @@ public static async Task InitializeAndInjectForLiveTests(CancellationToken cance var logger = loggerFactory.CreateLogger("CachingFileDownloader"); var cfd = new CachingFileDownloader(loggerFactory.CreateLogger()); - var edgeVersion = await ByondTest.GetEdgeVersion(Api.Models.EngineType.Byond, cfd, cancellationToken); + var edgeVersion = await EngineTest.GetEdgeVersion(Api.Models.EngineType.Byond, cfd, cancellationToken); await InitializeByondVersion(logger, edgeVersion.Version, new PlatformIdentifier().IsWindows, cancellationToken); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs similarity index 87% rename from tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs rename to tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs index 991281ac02a..6ca6ac32fbf 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ByondTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs @@ -26,9 +26,9 @@ namespace Tgstation.Server.Tests.Live.Instance { - sealed class ByondTest(IEngineClient byondClient, IJobsClient jobsClient, IFileDownloader fileDownloader, Api.Models.Instance metadata, EngineType engineType) : JobsRequiredTest(jobsClient) + sealed class EngineTest(IEngineClient engineClient, IJobsClient jobsClient, IFileDownloader fileDownloader, Api.Models.Instance metadata, EngineType engineType) : JobsRequiredTest(jobsClient) { - readonly IEngineClient byondClient = byondClient ?? throw new ArgumentNullException(nameof(byondClient)); + readonly IEngineClient engineClient = engineClient ?? throw new ArgumentNullException(nameof(engineClient)); readonly IFileDownloader fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); readonly Api.Models.Instance metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); @@ -111,7 +111,7 @@ async Task RunPartOne(CancellationToken cancellationToken) ValueTask TestInstallNullVersion(CancellationToken cancellationToken) => ApiAssert.ThrowsException( - () => byondClient.SetActiveVersion( + () => engineClient.SetActiveVersion( new EngineVersionRequest { EngineVersion = new EngineVersion @@ -133,7 +133,7 @@ async Task RunContinued(Task firstInstall, CancellationToken cancellationToken) async Task TestDeletes(CancellationToken cancellationToken) { - var deleteThisOneBecauseItWasntPartOfTheOriginalTest = await byondClient.DeleteVersion(new EngineVersionDeleteRequest + var deleteThisOneBecauseItWasntPartOfTheOriginalTest = await engineClient.DeleteVersion(new EngineVersionDeleteRequest { EngineVersion = new EngineVersion { @@ -144,7 +144,7 @@ async Task TestDeletes(CancellationToken cancellationToken) }, cancellationToken); await WaitForJob(deleteThisOneBecauseItWasntPartOfTheOriginalTest, 30, false, null, cancellationToken); - var nonExistentUninstallResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( + var nonExistentUninstallResponseTask = ApiAssert.ThrowsException(() => engineClient.DeleteVersion( new EngineVersionDeleteRequest { EngineVersion = new EngineVersion @@ -155,7 +155,7 @@ async Task TestDeletes(CancellationToken cancellationToken) }, cancellationToken), ErrorCode.ResourceNotPresent); - var uninstallResponseTask = byondClient.DeleteVersion( + var uninstallResponseTask = engineClient.DeleteVersion( new EngineVersionDeleteRequest { EngineVersion = new EngineVersion @@ -167,7 +167,7 @@ async Task TestDeletes(CancellationToken cancellationToken) }, cancellationToken); - var badBecauseActiveResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( + var badBecauseActiveResponseTask = ApiAssert.ThrowsException(() => engineClient.DeleteVersion( new EngineVersionDeleteRequest { EngineVersion = new EngineVersion @@ -194,7 +194,7 @@ async Task TestDeletes(CancellationToken cancellationToken) var byondDir = Path.Combine(metadata.Path, "Byond", testVersion.ToString()); Assert.IsFalse(Directory.Exists(byondDir)); - var newVersions = await byondClient.InstalledVersions(null, cancellationToken); + var newVersions = await engineClient.InstalledVersions(null, cancellationToken); Assert.IsNotNull(newVersions); Assert.AreEqual(1, newVersions.Count); Assert.AreEqual(testVersion.Version.Semver(), newVersions[0].EngineVersion.Version.Semver()); @@ -211,11 +211,11 @@ async Task TestInstallFakeVersion(CancellationToken cancellationToken) } }; - await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(newModel, null, cancellationToken), ErrorCode.ModelValidationFailure); + await ApiAssert.ThrowsException(() => engineClient.SetActiveVersion(newModel, null, cancellationToken), ErrorCode.ModelValidationFailure); newModel.EngineVersion.Engine = testEngine; - var test = await byondClient.SetActiveVersion(newModel, null, cancellationToken); + var test = await engineClient.SetActiveVersion(newModel, null, cancellationToken); Assert.IsNotNull(test.InstallJob); await WaitForJob(test.InstallJob, 60, true, ErrorCode.EngineDownloadFail, cancellationToken); } @@ -231,10 +231,10 @@ async Task TestInstallStable(CancellationToken cancellationToken) SourceSHA = testVersion.SourceSHA, } }; - var test = await byondClient.SetActiveVersion(newModel, null, cancellationToken); + var test = await engineClient.SetActiveVersion(newModel, null, cancellationToken); Assert.IsNotNull(test.InstallJob); await WaitForJob(test.InstallJob, 180, false, null, cancellationToken); - var currentShit = await byondClient.ActiveVersion(cancellationToken); + var currentShit = await engineClient.ActiveVersion(cancellationToken); Assert.AreEqual(newModel.EngineVersion, currentShit.EngineVersion); Assert.IsFalse(currentShit.EngineVersion.CustomIteration.HasValue); @@ -253,8 +253,8 @@ async Task TestInstallStable(CancellationToken cancellationToken) async Task TestNoVersion(CancellationToken cancellationToken) { - var allVersionsTask = byondClient.InstalledVersions(null, cancellationToken); - var currentShit = await byondClient.ActiveVersion(cancellationToken); + var allVersionsTask = engineClient.InstalledVersions(null, cancellationToken); + var currentShit = await engineClient.ActiveVersion(cancellationToken); Assert.IsNotNull(currentShit); Assert.IsNull(currentShit.EngineVersion); var otherShit = await allVersionsTask; @@ -289,7 +289,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) // get the bytes for stable await using var stableBytesMs = await TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(testVersion, null, cancellationToken), cancellationToken); - var test = await byondClient.SetActiveVersion( + var test = await engineClient.SetActiveVersion( new EngineVersionRequest { EngineVersion = new EngineVersion @@ -308,7 +308,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) // do it again. #1501 stableBytesMs.Seek(0, SeekOrigin.Begin); - var test2 = await byondClient.SetActiveVersion( + var test2 = await engineClient.SetActiveVersion( new EngineVersionRequest { EngineVersion = new EngineVersion @@ -326,12 +326,12 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) Assert.IsNotNull(test2.InstallJob); await WaitForJob(test2.InstallJob, 30, false, null, cancellationToken); - var newSettings = await byondClient.ActiveVersion(cancellationToken); + var newSettings = await engineClient.ActiveVersion(cancellationToken); Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 0), newSettings.EngineVersion.Version); Assert.AreEqual(2, newSettings.EngineVersion.CustomIteration); // test a few switches - var installResponse = await byondClient.SetActiveVersion(new EngineVersionRequest + var installResponse = await engineClient.SetActiveVersion(new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -341,7 +341,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) } }, null, cancellationToken); Assert.IsNull(installResponse.InstallJob); - await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(new EngineVersionRequest + await ApiAssert.ThrowsException(() => engineClient.SetActiveVersion(new EngineVersionRequest { EngineVersion = new EngineVersion { @@ -351,7 +351,7 @@ await ApiAssert.ThrowsException(() } }, null, cancellationToken), ErrorCode.EngineNonExistentCustomVersion); - installResponse = await byondClient.SetActiveVersion(new EngineVersionRequest + installResponse = await engineClient.SetActiveVersion(new EngineVersionRequest { EngineVersion = new EngineVersion { diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index c50f4d25673..26f00486bd7 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -34,6 +35,22 @@ sealed class InstanceTest(IInstanceManagerClient instanceManagerClient, IFileDow readonly InstanceManager instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager)); readonly ushort serverPort = serverPort; + public async Task RunLegacyByondTest( + IInstanceClient instanceClient, + CancellationToken cancellationToken) + { + var testVersion = await EngineTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); + await new LegacyByondTest( + instanceClient.Jobs, + fileDownloader, + new LegacyByondClient( + (IApiClient)instanceClient.Engine.GetType().GetProperty("ApiClient", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(instanceClient.Engine), + instanceClient.Metadata), + testVersion.Version, + instanceClient.Metadata) + .Run(cancellationToken); + } + public async Task RunTests( IInstanceClient instanceClient, ushort dmPort, @@ -42,14 +59,14 @@ public async Task RunTests( bool lowPrioDeployment, CancellationToken cancellationToken) { - var testVersion = await ByondTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); - var byondTest = new ByondTest(instanceClient.Engine, instanceClient.Jobs, fileDownloader, instanceClient.Metadata, testVersion.Engine.Value); + var testVersion = await EngineTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); + var engineTest = new EngineTest(instanceClient.Engine, instanceClient.Jobs, fileDownloader, instanceClient.Metadata, testVersion.Engine.Value); var chatTest = new ChatTest(instanceClient.ChatBots, instanceManagerClient, instanceClient.Jobs, instanceClient.Metadata); var configTest = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata); var repoTest = new RepositoryTest(instanceClient.Repository, instanceClient.Jobs); var dmTest = new DeploymentTest(instanceClient, instanceClient.Jobs, dmPort, ddPort, lowPrioDeployment, testVersion.Engine.Value); - var byondTask = byondTest.Run(cancellationToken, out var firstInstall); + var byondTask = engineTest.Run(cancellationToken, out var firstInstall); var chatTask = chatTest.RunPreWatchdog(cancellationToken); var repoLongJob = await repoTest.RunLongClone(cancellationToken); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/LegacyByondClient.cs b/tests/Tgstation.Server.Tests/Live/Instance/LegacyByondClient.cs new file mode 100644 index 00000000000..9793401d244 --- /dev/null +++ b/tests/Tgstation.Server.Tests/Live/Instance/LegacyByondClient.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +using Tgstation.Server.Api; +using Tgstation.Server.Api.Models.Response; +using Tgstation.Server.Client; +using Tgstation.Server.Host.Controllers.Legacy.Models; + +namespace Tgstation.Server.Tests.Live.Instance +{ + /// + sealed class LegacyByondClient : PaginatedClient + { + const string Route = Routes.Root + "Byond"; + + /// + /// The for the . + /// + readonly Api.Models.Instance instance; + + /// + /// Initializes a new instance of the class. + /// + /// The for the . + /// The value of . + public LegacyByondClient(IApiClient apiClient, Api.Models.Instance instance) + : base(apiClient) + { + this.instance = instance ?? throw new ArgumentNullException(nameof(instance)); + } + + /// + public ValueTask ActiveVersion(CancellationToken cancellationToken) => ApiClient.Read(Route, instance.Id!.Value, cancellationToken); + + /// + public ValueTask DeleteVersion(ByondVersionDeleteRequest deleteRequest, CancellationToken cancellationToken) + => ApiClient.Delete(Route, deleteRequest, instance.Id!.Value, cancellationToken); + + /// + public ValueTask> InstalledVersions(PaginationSettings paginationSettings, CancellationToken cancellationToken) + => ReadPaged(paginationSettings, Routes.ListRoute(Route), instance.Id, cancellationToken); + + /// + public async ValueTask SetActiveVersion(ByondVersionRequest installRequest, Stream zipFileStream, CancellationToken cancellationToken) + { + if (installRequest == null) + throw new ArgumentNullException(nameof(installRequest)); + if (installRequest.UploadCustomZip == true && zipFileStream == null) + throw new ArgumentNullException(nameof(zipFileStream)); + + var result = await ApiClient.Update( + Route, + installRequest, + instance.Id!.Value, + cancellationToken) + .ConfigureAwait(false); + + if (installRequest.UploadCustomZip == true) + await ApiClient.Upload(result, zipFileStream, cancellationToken).ConfigureAwait(false); + + return result; + } + } +} diff --git a/tests/Tgstation.Server.Tests/Live/Instance/LegacyByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/LegacyByondTest.cs new file mode 100644 index 00000000000..ef13665456e --- /dev/null +++ b/tests/Tgstation.Server.Tests/Live/Instance/LegacyByondTest.cs @@ -0,0 +1,240 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using System.Threading; + +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Api.Models.Request; +using Tgstation.Server.Api.Models.Response; +using Tgstation.Server.Api.Models; +using Tgstation.Server.Client; +using Tgstation.Server.Common.Extensions; +using Tgstation.Server.Host.Components.Engine; +using Tgstation.Server.Host.Configuration; + +using Tgstation.Server.Host.IO; + +using Tgstation.Server.Host.System; +using Tgstation.Server.Host.Controllers.Legacy.Models; +using Tgstation.Server.Client.Components; + +namespace Tgstation.Server.Tests.Live.Instance +{ + internal class LegacyByondTest : JobsRequiredTest + { + readonly LegacyByondClient byondClient; + readonly Version testVersion; + readonly Api.Models.Instance metadata; + + readonly IFileDownloader fileDownloader; + + public LegacyByondTest(IJobsClient jobsClient, IFileDownloader fileDownloader, LegacyByondClient byondClient, Version testVersion, Api.Models.Instance metadata) + : base(jobsClient) + { + this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); + this.byondClient = byondClient ?? throw new ArgumentNullException(nameof(byondClient)); + this.testVersion = testVersion ?? throw new ArgumentNullException(nameof(testVersion)); + this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); + } + + public async Task Run(CancellationToken cancellationToken) + { + await TestNoVersion(cancellationToken); + await TestInstallNullVersion(cancellationToken); + await TestInstallStable(cancellationToken); + await TestInstallFakeVersion(cancellationToken); + await TestCustomInstalls(cancellationToken); + await TestDeletes(cancellationToken); + } + + ValueTask TestInstallNullVersion(CancellationToken cancellationToken) + => ApiAssert.ThrowsException( + () => byondClient.SetActiveVersion( + new ByondVersionRequest(), + null, + cancellationToken), + ErrorCode.ModelValidationFailure); + + async Task TestDeletes(CancellationToken cancellationToken) + { + var deleteThisOneBecauseItWasntPartOfTheOriginalTest = await byondClient.DeleteVersion( + new ByondVersionDeleteRequest + { + Version = new Version(testVersion.Major, testVersion.Minor, 2), + }, cancellationToken); + await WaitForJob(deleteThisOneBecauseItWasntPartOfTheOriginalTest, 30, false, null, cancellationToken); + + var nonExistentUninstallResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( + new ByondVersionDeleteRequest + { + Version = new(509, 1000), + }, + cancellationToken), ErrorCode.ResourceNotPresent); + + var uninstallResponseTask = byondClient.DeleteVersion( + new ByondVersionDeleteRequest + { + Version = testVersion + }, + cancellationToken); + + var badBecauseActiveResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( + new ByondVersionDeleteRequest + { + Version = new Version(testVersion.Major, testVersion.Minor, 1), + }, + cancellationToken), ErrorCode.EngineCannotDeleteActiveVersion); + + await badBecauseActiveResponseTask; + + var uninstallJob = await uninstallResponseTask; + Assert.IsNotNull(uninstallJob); + + // Has to wait on deployment test possibly + var uninstallTask = WaitForJob(uninstallJob, 120, false, null, cancellationToken); + + await nonExistentUninstallResponseTask; + + await uninstallTask; + var byondDir = Path.Combine(metadata.Path, "Byond", testVersion.ToString()); + Assert.IsFalse(Directory.Exists(byondDir)); + + var newVersions = await byondClient.InstalledVersions(null, cancellationToken); + Assert.IsNotNull(newVersions); + Assert.AreEqual(1, newVersions.Count); + Assert.AreEqual(new Version(testVersion.Major, testVersion.Minor, 1), newVersions[0].Version); + } + + async Task TestInstallFakeVersion(CancellationToken cancellationToken) + { + var newModel = new ByondVersionRequest + { + Version = new Version(5011, 1385), + }; + + var test = await byondClient.SetActiveVersion(newModel, null, cancellationToken); + Assert.IsNotNull(test.InstallJob); + await WaitForJob(test.InstallJob, 60, true, ErrorCode.EngineDownloadFail, cancellationToken); + } + + async Task TestInstallStable(CancellationToken cancellationToken) + { + var newModel = new ByondVersionRequest + { + Version = testVersion, + }; + var test = await byondClient.SetActiveVersion(newModel, null, cancellationToken); + Assert.IsNotNull(test.InstallJob); + await WaitForJob(test.InstallJob, 180, false, null, cancellationToken); + var currentShit = await byondClient.ActiveVersion(cancellationToken); + Assert.AreEqual(newModel.Version.Semver(), currentShit.Version.Semver()); + + var dreamMaker = "DreamMaker"; + if (new PlatformIdentifier().IsWindows) + dreamMaker += ".exe"; + + var dreamMakerDir = Path.Combine(metadata.Path, "Byond", newModel.Version.ToString(), "byond", "bin"); + + Assert.IsTrue(Directory.Exists(dreamMakerDir), $"Directory {dreamMakerDir} does not exist!"); + Assert.IsTrue( + File.Exists( + Path.Combine(dreamMakerDir, dreamMaker)), + $"Missing DreamMaker executable! Dir contents: {string.Join(", ", Directory.GetFileSystemEntries(dreamMakerDir))}"); + } + + async Task TestNoVersion(CancellationToken cancellationToken) + { + var allVersionsTask = byondClient.InstalledVersions(null, cancellationToken); + var currentShit = await byondClient.ActiveVersion(cancellationToken); + Assert.IsNotNull(currentShit); + Assert.IsNull(currentShit.Version); + var otherShit = await allVersionsTask; + Assert.IsNotNull(otherShit); + Assert.AreEqual(0, otherShit.Count); + } + + async Task TestCustomInstalls(CancellationToken cancellationToken) + { + var generalConfigOptionsMock = new Mock>(); + generalConfigOptionsMock.SetupGet(x => x.Value).Returns(new GeneralConfiguration()); + var sessionConfigOptionsMock = new Mock>(); + sessionConfigOptionsMock.SetupGet(x => x.Value).Returns(new SessionConfiguration()); + + var assemblyInformationProvider = new AssemblyInformationProvider(); + + IEngineInstaller byondInstaller = new PlatformIdentifier().IsWindows + ? new WindowsByondInstaller( + Mock.Of(), + Mock.Of(), + fileDownloader, + generalConfigOptionsMock.Object, + Mock.Of>()) + : new PosixByondInstaller( + Mock.Of(), + Mock.Of(), + fileDownloader, + Mock.Of>()); + + using var windowsByondInstaller = byondInstaller as WindowsByondInstaller; + + // get the bytes for stable + await using var stableBytesMs = await TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(new EngineVersion + { + Version = testVersion, + Engine = EngineType.Byond, + }, null, cancellationToken), cancellationToken); + + var test = await byondClient.SetActiveVersion( + new ByondVersionRequest + { + Version = testVersion, + UploadCustomZip = true, + }, + stableBytesMs, + cancellationToken); + + Assert.IsNotNull(test.InstallJob); + await WaitForJob(test.InstallJob, 30, false, null, cancellationToken); + + // do it again. #1501 + stableBytesMs.Seek(0, SeekOrigin.Begin); + var test2 = await byondClient.SetActiveVersion( + new ByondVersionRequest + { + Version = testVersion, + UploadCustomZip = true, + }, + stableBytesMs, + cancellationToken); + + Assert.IsNotNull(test2.InstallJob); + await WaitForJob(test2.InstallJob, 30, false, null, cancellationToken); + + var newSettings = await byondClient.ActiveVersion(cancellationToken); + Assert.AreEqual(new Version(testVersion.Major, testVersion.Minor, 2), newSettings.Version); + + // test a few switches + var installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest + { + Version = testVersion, + }, null, cancellationToken); + Assert.IsNull(installResponse.InstallJob); + await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(new ByondVersionRequest + { + Version = new Version(testVersion.Major, testVersion.Minor, 3), + }, null, cancellationToken), ErrorCode.EngineNonExistentCustomVersion); + + installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest + { + Version = new Version(testVersion.Major, testVersion.Minor, 1), + }, null, cancellationToken); + Assert.IsNull(installResponse.InstallJob); + } + } +} diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 229bdeade64..0b576de6d70 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1141,9 +1141,11 @@ async Task FailFast(Task task) var instanceManagerTest = new InstanceManagerTest(adminClient, server.Directory); var compatInstanceTask = instanceManagerTest.CreateTestInstance("CompatTestsInstance", cancellationToken); var odInstanceTask = instanceManagerTest.CreateTestInstance("OdTestsInstance", cancellationToken); + var byondApiCompatInstanceTask = instanceManagerTest.CreateTestInstance("BCAPITestsInstance", cancellationToken); instance = await instanceManagerTest.CreateTestInstance("LiveTestsInstance", cancellationToken); var compatInstance = await compatInstanceTask; var odInstance = await odInstanceTask; + var byondApiCompatInstance = await byondApiCompatInstanceTask; var instancesTest = FailFast(instanceManagerTest.RunPreTest(cancellationToken)); Assert.IsTrue(Directory.Exists(instance.Path)); var instanceClient = adminClient.Instances.CreateClient(instance); @@ -1158,10 +1160,19 @@ async Task FailFast(Task task) async Task RunInstanceTests() { + var byondApiCompatTests = FailFast( + instanceTest + .RunLegacyByondTest( + adminClient.Instances.CreateClient(byondApiCompatInstance), + cancellationToken)); + + if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization + await byondApiCompatTests; + var odCompatTests = FailFast( instanceTest .RunCompatTests( - await ByondTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellationToken), + await EngineTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellationToken), adminClient.Instances.CreateClient(odInstance), odDMPort, odDDPort, @@ -1204,6 +1215,7 @@ await FailFast( await compatTests; await odCompatTests; + await byondApiCompatTests; } var instanceTests = RunInstanceTests(); @@ -1367,7 +1379,7 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) preStartupTime = DateTimeOffset.UtcNow; serverTask = server.Run(cancellationToken).AsTask(); long expectedCompileJobId, expectedStaged; - var edgeVersion = await ByondTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); + var edgeVersion = await EngineTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); using (var adminClient = await CreateAdminClient(server.Url, cancellationToken)) { var instanceClient = adminClient.Instances.CreateClient(instance); From d76ed9199afe1f4b9d9751ccfc1993a0fd543302 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 03:04:34 -0400 Subject: [PATCH 111/717] FUCKING SOCKET REUSE --- .../Components/Session/SessionControllerFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 6daf9cb6d42..86e24f7f633 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -256,7 +256,7 @@ public async ValueTask LaunchNew( if (engineType == EngineType.Byond) await CheckPagerIsNotRunning(); else if (engineType == EngineType.OpenDream && platformIdentifier.IsWindows) - await asyncDelayer.Delay(TimeSpan.FromSeconds(1), cancellationToken); // prevent socket reuse after bind test + await asyncDelayer.Delay(TimeSpan.FromSeconds(2), cancellationToken); // prevent socket reuse after bind test string outputFilePath = null; var preserveLogFile = true; From 04bf89f646194c3c01228e2c8653644ec2a3a525 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 03:11:49 -0400 Subject: [PATCH 112/717] More DMAPI updates for OpenDream --- build/Version.props | 2 +- src/DMAPI/tgs.dm | 21 +++++++++++------- src/DMAPI/tgs/core/core.dm | 7 ++++++ .../Components/Deployment/DreamMaker.cs | 18 +++++++-------- .../Components/Engine/EngineManager.cs | 6 ++--- .../Components/Events/EventScriptAttribute.cs | 11 +++++----- .../Components/Events/EventType.cs | 22 +++++++++---------- .../Components/StaticFiles/Configuration.cs | 13 ++++++----- 8 files changed, 57 insertions(+), 43 deletions(-) diff --git a/build/Version.props b/build/Version.props index 31e62df8db4..1d5bd1756f1 100644 --- a/build/Version.props +++ b/build/Version.props @@ -9,7 +9,7 @@ 6.0.1 12.0.0 13.0.0 - 6.6.0 + 7.0.0 5.7.0 1.4.0 1.2.1 diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm index 6d35cf6593e..d9ebdb6a686 100644 --- a/src/DMAPI/tgs.dm +++ b/src/DMAPI/tgs.dm @@ -1,6 +1,6 @@ // tgstation-server DMAPI -#define TGS_DMAPI_VERSION "6.6.0" +#define TGS_DMAPI_VERSION "7.0.0" // All functions and datums outside this document are subject to change with any version and should not be relied on. @@ -73,12 +73,12 @@ #define TGS_EVENT_REPO_MERGE_PULL_REQUEST 3 /// Before the repository makes a sychronize operation. Parameters: Absolute repostiory path. #define TGS_EVENT_REPO_PRE_SYNCHRONIZE 4 -/// Before a BYOND install operation begins. Parameters: [/datum/tgs_version] of the installing BYOND, engine type of the installing BYOND. -#define TGS_EVENT_BYOND_INSTALL_START 5 -/// When a BYOND install operation fails. Parameters: Error message -#define TGS_EVENT_BYOND_INSTALL_FAIL 6 -/// When the active BYOND version changes. Parameters: (Nullable) [/datum/tgs_version] of the current BYOND, [/datum/tgs_version] of the new BYOND, engine type of the current BYOND, engine type of the new BYOND. -#define TGS_EVENT_BYOND_ACTIVE_VERSION_CHANGE 7 +/// Before a engine install operation begins. Parameters: Version string of the installing engine. +#define TGS_EVENT_ENGINE_INSTALL_START 5 +/// When a engine install operation fails. Parameters: Error message +#define TGS_EVENT_ENGINE_INSTALL_FAIL 6 +/// When the active engine version changes. Parameters: (Nullable) Version string of the current engine, version string of the new engine. +#define TGS_EVENT_ENGINE_ACTIVE_VERSION_CHANGE 7 /// When the compiler starts running. Parameters: Game directory path, origin commit SHA. #define TGS_EVENT_COMPILE_START 8 /// When a compile is cancelled. No parameters. @@ -108,7 +108,7 @@ // #define TGS_EVENT_DREAM_DAEMON_LAUNCH 22 /// After a single submodule update is performed. Parameters: Updated submodule name. #define TGS_EVENT_REPO_SUBMODULE_UPDATE 23 -/// After CodeModifications are applied, before DreamMaker is run. Parameters: Game directory path, origin commit sha, byond version. +/// After CodeModifications are applied, before DreamMaker is run. Parameters: Game directory path, origin commit sha, version string of the used engine. #define TGS_EVENT_PRE_DREAM_MAKER 24 /// Whenever a deployment folder is deleted from disk. Parameters: Game directory path. #define TGS_EVENT_DEPLOYMENT_CLEANUP 25 @@ -122,6 +122,7 @@ /// The watchdog will restart on reboot. #define TGS_REBOOT_MODE_RESTART 2 +// Note that security levels are currently meaningless in OpenDream /// DreamDaemon Trusted security level. #define TGS_SECURITY_TRUSTED 0 /// DreamDaemon Safe security level. @@ -447,6 +448,10 @@ /world/proc/TgsVersion() return +/// Returns the running engine type +/world/proc/TgsEngine() + return + /// Returns the current [/datum/tgs_version] of the DMAPI being used if it was activated, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsApiVersion() return diff --git a/src/DMAPI/tgs/core/core.dm b/src/DMAPI/tgs/core/core.dm index 41a04733945..18a51d617a8 100644 --- a/src/DMAPI/tgs/core/core.dm +++ b/src/DMAPI/tgs/core/core.dm @@ -107,6 +107,13 @@ if(api) return api.ApiVersion() +/world/TgsEngine() +#ifdef OPENDREAM + return TGS_ENGINE_TYPE_OPENDREAM +#else + return TGS_ENGINE_TYPE_BYOND +#endif + /world/TgsInstanceName() var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) if(api) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index 3b929318107..800929493d1 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -548,7 +548,7 @@ await RunCompileJob( /// The to run and populate. /// The to use. /// The to use. - /// The to use. + /// The to use. /// The to use. /// The to use. /// The for the operation. @@ -558,7 +558,7 @@ async ValueTask RunCompileJob( Models.CompileJob job, Api.Models.Internal.DreamMakerSettings dreamMakerSettings, DreamDaemonLaunchParameters launchParameters, - IEngineExecutableLock byondLock, + IEngineExecutableLock engineLock, IRepository repository, IRemoteDeploymentManager remoteDeploymentManager, CancellationToken cancellationToken) @@ -586,7 +586,7 @@ await eventConsumer.HandleEvent( { resolvedOutputDirectory, repoOrigin.ToString(), - byondLock.Version.ToString(), + engineLock.Version.ToString(), }, true, cancellationToken); @@ -625,17 +625,17 @@ await eventConsumer.HandleEvent( { resolvedOutputDirectory, repoOrigin.ToString(), - byondLock.Version.ToString(), + engineLock.Version.ToString(), }, true, cancellationToken); // run compiler progressReporter.StageName = "Running DreamMaker"; - var compileSuceeded = await RunDreamMaker(byondLock, job, cancellationToken); + var compileSuceeded = await RunDreamMaker(engineLock, job, cancellationToken); // Session takes ownership of the lock and Disposes it so save this for later - var byondVersion = byondLock.Version; + var engineVersion = engineLock.Version; // verify api try @@ -650,7 +650,7 @@ await VerifyApi( launchParameters.StartupTimeout.Value, dreamMakerSettings.ApiValidationSecurityLevel.Value, job, - byondLock, + engineLock, dreamMakerSettings.ApiValidationPort.Value, dreamMakerSettings.RequireDMApiValidation.Value, launchParameters.LogOutput.Value, @@ -666,7 +666,7 @@ await eventConsumer.HandleEvent( { resolvedOutputDirectory, compileSuceeded ? "1" : "0", - byondVersion.ToString(), + engineVersion.ToString(), }, true, cancellationToken); @@ -679,7 +679,7 @@ await eventConsumer.HandleEvent( new List { resolvedOutputDirectory, - byondVersion.ToString(), + engineVersion.ToString(), }, true, cancellationToken); diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index 3a1097bd89b..d6425be223e 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -143,7 +143,7 @@ public async ValueTask ChangeVersion( var stringVersion = version.ToString(); await ioManager.WriteAllBytes(ActiveVersionFileName, Encoding.UTF8.GetBytes(stringVersion), cancellationToken); await eventConsumer.HandleEvent( - EventType.ByondActiveVersionChange, + EventType.EngineActiveVersionChange, new List { ActiveVersion?.ToString(), @@ -463,7 +463,7 @@ async ValueTask AssertAndLockVersion( progressReporter.StageName = "Running event"; var versionString = version.ToString(); - await eventConsumer.HandleEvent(EventType.ByondInstallStart, new List { versionString }, false, cancellationToken); + await eventConsumer.HandleEvent(EventType.EngineInstallStart, new List { versionString }, false, cancellationToken); await InstallVersionFiles(progressReporter, version, customVersionStream, cancellationToken); @@ -472,7 +472,7 @@ async ValueTask AssertAndLockVersion( catch (Exception ex) { if (ex is not OperationCanceledException) - await eventConsumer.HandleEvent(EventType.ByondInstallFail, new List { ex.Message }, false, cancellationToken); + await eventConsumer.HandleEvent(EventType.EngineInstallFail, new List { ex.Message }, false, cancellationToken); lock (installedVersions) installedVersions.Remove(version); diff --git a/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs b/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs index c1b14e7b678..585954544be 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace Tgstation.Server.Host.Components.Events { @@ -9,17 +10,17 @@ namespace Tgstation.Server.Host.Components.Events sealed class EventScriptAttribute : Attribute { /// - /// The name of the script the event script the runs. + /// The name and order of the scripts the event script the runs. /// - public string ScriptName { get; } + public IReadOnlyList ScriptNames { get; } /// /// Initializes a new instance of the class. /// - /// The value of . - public EventScriptAttribute(string scriptName) + /// The value of . + public EventScriptAttribute(params string[] scriptNames) { - ScriptName = scriptName ?? throw new ArgumentNullException(nameof(scriptName)); + ScriptNames = ScriptNames ?? throw new ArgumentNullException(nameof(scriptNames)); } } } diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs index 0a54518a248..e7193a34d3f 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventType.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs @@ -1,7 +1,7 @@ namespace Tgstation.Server.Host.Components.Events { /// - /// Types of events. Mirror in tgs.dm. + /// Types of events. Mirror in tgs.dm. Prefer last listed name for script. /// public enum EventType { @@ -39,23 +39,23 @@ public enum EventType /// /// Parameters: Version being installed /// - [EventScript("ByondInstallStart")] - ByondInstallStart, + [EventScript("ByondInstallStart", "EngineInstallStart")] + EngineInstallStart, /// /// Parameters: Error string /// - [EventScript("ByondInstallFail")] - ByondInstallFail, + [EventScript("ByondInstallFail", "EngineInstallFail")] + EngineInstallFail, /// /// Parameters: Old active version, new active version /// - [EventScript("ByondActiveVersionChange")] - ByondActiveVersionChange, + [EventScript("ByondActiveVersionChange", "EngineActiveVersionChange")] + EngineActiveVersionChange, /// - /// After the repo is copied, before CodeModifications are applied. Parameters: Game directory path, origin commit sha, byond version + /// After the repo is copied, before CodeModifications are applied. Parameters: Game directory path, origin commit sha, engine version string /// [EventScript("PreCompile")] CompileStart, @@ -67,13 +67,13 @@ public enum EventType CompileCancelled, /// - /// Parameters: Game directory path, "1" if compile succeeded and api validation failed, "0" otherwise, BYOND version used + /// Parameters: Game directory path, "1" if compile succeeded and api validation failed, "0" otherwise, engine version string /// [EventScript("CompileFailure")] CompileFailure, /// - /// Parameters: Game directory path, BYOND version used + /// Parameters: Game directory path, engine version string /// [EventScript("PostCompile")] CompileComplete, @@ -151,7 +151,7 @@ public enum EventType RepoSubmoduleUpdate, /// - /// After CodeModifications are applied, before DreamMaker is run. Parameters: Game directory path, origin commit sha, byond version + /// After CodeModifications are applied, before DreamMaker is run. Parameters: Game directory path, origin commit sha, engine version string /// [EventScript("PreDreamMaker")] PreDreamMaker, diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs index 2b19803126d..35e9d2d34c5 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs @@ -71,18 +71,18 @@ sealed class Configuration : IConfiguration /// /// Map of s to the filename of the event scripts they trigger. /// - static readonly IReadOnlyDictionary EventTypeScriptFileNameMap = new Dictionary( + static readonly IReadOnlyDictionary> EventTypeScriptFileNameMap = new Dictionary>( Enum.GetValues(typeof(EventType)) .OfType() .Select( - eventType => new KeyValuePair( + eventType => new KeyValuePair>( eventType, typeof(EventType) .GetField(eventType.ToString()) .GetCustomAttributes(false) .OfType() .First() - .ScriptName))); + .ScriptNames))); /// /// The for . @@ -606,7 +606,7 @@ public async ValueTask HandleEvent(EventType eventType, IEnumerable para await EnsureDirectories(cancellationToken); - if (!EventTypeScriptFileNameMap.TryGetValue(eventType, out var scriptName)) + if (!EventTypeScriptFileNameMap.TryGetValue(eventType, out var scriptNames)) return; // always execute in serial @@ -617,12 +617,13 @@ public async ValueTask HandleEvent(EventType eventType, IEnumerable para var scriptFiles = files .Select(x => ioManager.GetFileName(x)) - .Where(x => x.StartsWith(scriptName, StringComparison.Ordinal)) + .Where(x => scriptNames.Any( + scriptName => x.StartsWith(scriptName, StringComparison.Ordinal))) .ToList(); if (!scriptFiles.Any()) { - logger.LogTrace("No event scripts starting with \"{scriptName}\" detected", scriptName); + logger.LogTrace("No event scripts starting with \"{scriptName}\" detected", String.Join("\" or \"", scriptNames)); return; } From a71f23ee292faa8d4050bccd7a180c08e02ad1aa Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 09:18:31 -0400 Subject: [PATCH 113/717] Fix event tests --- .../Components/Events/EventScriptAttribute.cs | 2 +- .../Components/Events/TestEventScriptAttribute.cs | 5 +++-- .../Components/Events/TestEventType.cs | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs b/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs index 585954544be..ba93d34cf95 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs @@ -20,7 +20,7 @@ sealed class EventScriptAttribute : Attribute /// The value of . public EventScriptAttribute(params string[] scriptNames) { - ScriptNames = ScriptNames ?? throw new ArgumentNullException(nameof(scriptNames)); + ScriptNames = scriptNames ?? throw new ArgumentNullException(nameof(scriptNames)); } } } diff --git a/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventScriptAttribute.cs b/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventScriptAttribute.cs index 4f9e4501503..232f8767d65 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventScriptAttribute.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventScriptAttribute.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; +using System.Linq; namespace Tgstation.Server.Host.Components.Events.Tests @@ -14,8 +15,8 @@ public sealed class TestEventScriptAttribute public void TestConstruction() { Assert.ThrowsException(() => new EventScriptAttribute(null)); - var test = new EventScriptAttribute("test"); - Assert.AreEqual("test", test.ScriptName); + var test = new EventScriptAttribute("test1", "test2"); + Assert.IsTrue(test.ScriptNames.SequenceEqual(["test1", "test2"])); } } } diff --git a/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventType.cs b/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventType.cs index 9c1a467160e..fcd032f60da 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventType.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Events/TestEventType.cs @@ -22,7 +22,8 @@ public void TestAllEventTypesHaveUniqueEventScriptAttributes() Assert.AreEqual(1, list.Count, $"EventType: {eventType}"); var attribute = list.First(); - Assert.IsTrue(allScripts.Add(attribute.ScriptName), $"Non-unique script Name: {attribute.ScriptName}"); + foreach (var scriptName in attribute.ScriptNames) + Assert.IsTrue(allScripts.Add(scriptName), $"Non-unique script Names: {scriptName}"); } } } From 33f0933b0da5d1afdfdfcb33ce3675968174f3fe Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 09:25:51 -0400 Subject: [PATCH 114/717] Stop spamming firewall exceptions on dev machines --- tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs index aff760753e2..b2430e68d2c 100644 --- a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs +++ b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs @@ -135,6 +135,7 @@ public LiveTestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth "General:ByondTopicTimeout=10000", $"Session:HighPriorityLiveDreamDaemon={HighPriorityDreamDaemon}", $"Session:LowPriorityDeploymentProcesses={LowPriorityDeployments}", + $"General:SkipAddingByondFirewallException={!TestingUtils.RunningInGitHubActions}", }; swarmArgs = new List(); From dfff65cad720e30fe81b2b71b97c703abfe2895f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 09:31:07 -0400 Subject: [PATCH 115/717] Respect `SkipAddingByondFirewallException` for OD --- .../Components/Engine/OpenDreamInstaller.cs | 10 +++++----- .../Components/Engine/WindowsOpenDreamInstaller.cs | 3 +++ src/Tgstation.Server.Host/appsettings.yml | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 115ec4f0419..fddff557ba6 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -64,7 +64,7 @@ class OpenDreamInstaller : EngineInstallerBase /// /// The for the . /// - readonly GeneralConfiguration generalConfiguration; + protected GeneralConfiguration GeneralConfiguration { get; } /// /// Initializes a new instance of the class. @@ -74,7 +74,7 @@ class OpenDreamInstaller : EngineInstallerBase /// The value of . /// The value of . /// The value of . - /// The containing value of . + /// The containing value of . public OpenDreamInstaller( IIOManager ioManager, ILogger logger, @@ -87,7 +87,7 @@ public OpenDreamInstaller( this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); ProcessExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); this.repositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager)); - generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); + GeneralConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } /// @@ -116,7 +116,7 @@ public override async ValueTask DownloadVersion(EngineV var progressSection1 = jobProgressReporter?.CreateSection("Updating OpenDream git repository", 0.5f); var repo = await repositoryManager.CloneRepository( - generalConfiguration.OpenDreamGitUrl, + GeneralConfiguration.OpenDreamGitUrl, null, null, null, @@ -142,7 +142,7 @@ await repo.FetchOrigin( var progressSection2 = jobProgressReporter?.CreateSection("Checking out OpenDream version", 0.5f); var committish = version.SourceSHA - ?? $"{generalConfiguration.OpenDreamGitTagPrefix}{version.Version.Semver()}"; + ?? $"{GeneralConfiguration.OpenDreamGitTagPrefix}{version.Version.Semver()}"; await repo.CheckoutObject( committish, diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index eb31f462faa..71c35eb7652 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -91,6 +91,9 @@ protected override async ValueTask HandleExtremelyLongPathOperation(FuncA representing the running operation. async ValueTask AddServerFirewallException(EngineVersion version, string path, CancellationToken cancellationToken) { + if (GeneralConfiguration.SkipAddingByondFirewallException) + return; + GetExecutablePaths(path, out var serverExePath, out _); int exitCode; diff --git a/src/Tgstation.Server.Host/appsettings.yml b/src/Tgstation.Server.Host/appsettings.yml index 30463394955..82cb960bf38 100644 --- a/src/Tgstation.Server.Host/appsettings.yml +++ b/src/Tgstation.Server.Host/appsettings.yml @@ -14,7 +14,7 @@ General: InstanceLimit: 10 # Maximum number of allowed instances ValidInstancePaths: # An array of directories instances may be created in (either directly or as a subdirectory). null removes the restriction HostApiDocumentation: false # Make HTTP API documentation available at /swagger/v1/swagger.json - SkipAddingByondFirewallException: false # Windows Only: Prevent running netsh.exe to add a firewall exception for installed DreamDaemon binaries + SkipAddingByondFirewallException: false # Windows Only: Prevent running netsh.exe to add a firewall exception for installed engine binaries DeploymentDirectoryCopyTasksPerCore: 100 # Maximum number of concurrent file copy operations PER available CPU core OpenDreamGitUrl: https://github.com/OpenDreamProject/OpenDream # The repository to retrieve OpenDream from OpenDreamGitTagPrefix: v # The prefix to the OpenDream semver as tags appear in the git repository From c462fabe8e6fe211ed7013b2e86873223038c3a2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 09:38:28 -0400 Subject: [PATCH 116/717] Use deterministic temp paths in integration tests --- tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs | 2 +- tests/Tgstation.Server.Tests/TestVersions.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs index b2430e68d2c..0d40229b190 100644 --- a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs +++ b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs @@ -84,7 +84,7 @@ public LiveTestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth Assert.IsTrue(port >= 10000); // for testing bridge request limit Directory = BaseDirectory; - Directory = Path.Combine(Directory, Guid.NewGuid().ToString()); + Directory = Path.Combine(Directory, swarmConfiguration?.Identifier ?? "default"); System.IO.Directory.CreateDirectory(Directory); string urlString = $"http://localhost:{port}"; Url = new Uri(urlString); diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index cba96b07e00..d8ade9ff910 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -30,6 +30,7 @@ using System.Net; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models; +using Tgstation.Server.Tests.Live; namespace Tgstation.Server.Tests { @@ -210,7 +211,7 @@ await CachingFileDownloader.InitializeByondVersion( loggerFactory); var ioManager = new DefaultIOManager(); - var tempPath = Path.GetTempFileName(); + var tempPath = ioManager.ConcatPath(LiveTestingServer.BaseDirectory, "mapthreads"); await ioManager.DeleteFile(tempPath, default); await ioManager.CreateDirectory(tempPath, default); try From 7082b7eb8e22ec8dbd0cd8c4c093e0eb0e28deea Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 09:41:59 -0400 Subject: [PATCH 117/717] Avoid using preview language feature --- .../Components/Engine/WindowsByondInstaller.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 95950c06d64..9ce8e3cd4df 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -264,7 +264,7 @@ async ValueTask AddDreamDaemonToFirewall(EngineVersion version, string path, Can if (usesDDExe) await IOManager.WriteAllBytes( IOManager.ConcatPath(path, TgsFirewalledDDFile), - [], + Array.Empty(), cancellationToken); } } From 98e1c1905cd4304028c1fd2d90ed47f0996bdb3e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 10:08:51 -0400 Subject: [PATCH 118/717] Possibly fix address reuse issue forever Child processes may have been ~~inheriting~~ stealing the bind test handle. --- .../Session/SessionControllerFactory.cs | 5 +-- .../Extensions/SocketExtensions.cs | 41 ++++++++++--------- .../System/ProcessExecutor.cs | 32 ++++++++++++++- 3 files changed, 55 insertions(+), 23 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 86e24f7f633..d1ba7ff2c63 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -217,7 +217,6 @@ public async ValueTask LaunchNew( if (!launchParameters.Port.HasValue) throw new InvalidOperationException("Given port is null!"); - PortBindTest(launchParameters.Port.Value); switch (dmbProvider.CompileJob.MinimumSecurityLevel) { case DreamDaemonSecurity.Ultrasafe: @@ -255,8 +254,8 @@ public async ValueTask LaunchNew( var engineType = dmbProvider.EngineVersion.Engine.Value; if (engineType == EngineType.Byond) await CheckPagerIsNotRunning(); - else if (engineType == EngineType.OpenDream && platformIdentifier.IsWindows) - await asyncDelayer.Delay(TimeSpan.FromSeconds(2), cancellationToken); // prevent socket reuse after bind test + + PortBindTest(launchParameters.Port.Value); string outputFilePath = null; var preserveLogFile = true; diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs index 948aedbc72e..75adcf9a258 100644 --- a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs @@ -1,6 +1,8 @@ using System.Net; using System.Net.Sockets; +using Tgstation.Server.Host.System; + namespace Tgstation.Server.Host.Extensions { /// @@ -14,26 +16,27 @@ static class SocketExtensions /// The port number to bind to. /// If IPV6 should be tested as well. public static void BindTest(ushort port, bool includeIPv6) - { - using var socket = new Socket( - includeIPv6 - ? AddressFamily.InterNetworkV6 - : AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.Tcp); + => ProcessExecutor.WithProcessLaunchExclusivity(() => + { + using var socket = new Socket( + includeIPv6 + ? AddressFamily.InterNetworkV6 + : AddressFamily.InterNetwork, + SocketType.Stream, + ProtocolType.Tcp); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); - if (includeIPv6) - socket.DualMode = true; + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); + if (includeIPv6) + socket.DualMode = true; - socket.Bind( - new IPEndPoint( - includeIPv6 - ? IPAddress.IPv6Any - : IPAddress.Any, - port)); - } + socket.Bind( + new IPEndPoint( + includeIPv6 + ? IPAddress.IPv6Any + : IPAddress.Any, + port)); + }); } } diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index 581977bb5b4..e680b092566 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -13,6 +13,11 @@ namespace Tgstation.Server.Host.System /// sealed class ProcessExecutor : IProcessExecutor { + /// + /// for . + /// + static readonly ReaderWriterLockSlim ExclusiveProcessLaunchLock = new (); + /// /// The for the . /// @@ -33,6 +38,23 @@ sealed class ProcessExecutor : IProcessExecutor /// readonly ILoggerFactory loggerFactory; + /// + /// Runs a given making sure to not launch any processes while its running. + /// + /// The to execute. + public static void WithProcessLaunchExclusivity(Action action) + { + ExclusiveProcessLaunchLock.EnterWriteLock(); + try + { + action(); + } + finally + { + ExclusiveProcessLaunchLock.ExitWriteLock(); + } + } + /// /// Initializes a new instance of the class. /// @@ -127,7 +149,15 @@ public IProcess LaunchProcess( try { - handle.Start(); + ExclusiveProcessLaunchLock.EnterReadLock(); + try + { + handle.Start(); + } + finally + { + ExclusiveProcessLaunchLock.ExitReadLock(); + } processStartTcs?.SetResult(); } From e9d3892325bb112c5e9c09e14ece6f0bb7086e4f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 11:16:15 -0400 Subject: [PATCH 119/717] Log OpenDream build exit code --- .../Components/Engine/OpenDreamInstaller.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index fddff557ba6..81734db3d51 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -229,7 +229,11 @@ await HandleExtremelyLongPathOperation( true, true); buildExitCode = await buildProcess.Lifetime; - Logger.LogDebug("Build output:{newLine}{output}", Environment.NewLine, await buildProcess.GetCombinedOutput(cancellationToken)); + Logger.LogDebug( + "OpenDream build exited with code {exitCode}:{newLine}{output}", + buildExitCode, + Environment.NewLine, + await buildProcess.GetCombinedOutput(cancellationToken)); }, sourcePath, cancellationToken); From 6c4046ca8c3425fa91ebdbe7b1e3c70e3c5b7b90 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 11:17:32 -0400 Subject: [PATCH 120/717] Fix temp path issue in version tests --- tests/Tgstation.Server.Tests/TestVersions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index d8ade9ff910..78390936df0 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -212,7 +212,6 @@ await CachingFileDownloader.InitializeByondVersion( var ioManager = new DefaultIOManager(); var tempPath = ioManager.ConcatPath(LiveTestingServer.BaseDirectory, "mapthreads"); - await ioManager.DeleteFile(tempPath, default); await ioManager.CreateDirectory(tempPath, default); try { From ef8b2e860f3f4cc68e8ff904ac83255553e991c6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 11:26:08 -0400 Subject: [PATCH 121/717] SocketOption.DontLinger is Windows only --- .../Components/InstanceManager.cs | 10 +++++++++- .../Session/SessionControllerFactory.cs | 2 +- .../Extensions/SocketExtensions.cs | 15 +++++++++++---- src/Tgstation.Server.Host/Utils/PortAllocator.cs | 11 ++++++++++- .../Live/Instance/WatchdogTest.cs | 2 +- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index ec66af63b1d..e790294c090 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -94,6 +94,11 @@ sealed class InstanceManager : /// readonly IConsole console; + /// + /// The for the . + /// + readonly IPlatformIdentifier platformIdentifier; + /// /// The for the . /// @@ -168,6 +173,7 @@ sealed class InstanceManager : /// The value of . /// The value of . /// The value of . + /// The value of . /// The containing the value of . /// The containing the value of . /// The value of . @@ -183,6 +189,7 @@ public InstanceManager( IServerPortProvider serverPortProvider, ISwarmServiceController swarmServiceController, IConsole console, + IPlatformIdentifier platformIdentifier, IOptions generalConfigurationOptions, IOptions swarmConfigurationOptions, ILogger logger) @@ -198,6 +205,7 @@ public InstanceManager( this.serverPortProvider = serverPortProvider ?? throw new ArgumentNullException(nameof(serverPortProvider)); this.swarmServiceController = swarmServiceController ?? throw new ArgumentNullException(nameof(swarmServiceController)); this.console = console ?? throw new ArgumentNullException(nameof(console)); + this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); swarmConfiguration = swarmConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(swarmConfigurationOptions)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -643,7 +651,7 @@ void CheckSystemCompatibility() // This runs before the real socket is opened, ensures we don't perform reattaches unless we're fairly certain the bind won't fail // If it does fail, DD will be killed. - SocketExtensions.BindTest(serverPortProvider.HttpApiPort, true); + SocketExtensions.BindTest(platformIdentifier, serverPortProvider.HttpApiPort, true); } /// diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index d1ba7ff2c63..96f28e042e5 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -135,7 +135,7 @@ void PortBindTest(ushort port) try { logger.LogTrace("Bind test: {port}", port); - SocketExtensions.BindTest(port, false); + SocketExtensions.BindTest(platformIdentifier, port, false); } catch (SocketException ex) when (ex.SocketErrorCode == SocketError.AddressAlreadyInUse) { diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs index 75adcf9a258..3c5d076e723 100644 --- a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs @@ -1,4 +1,5 @@ -using System.Net; +using System; +using System.Net; using System.Net.Sockets; using Tgstation.Server.Host.System; @@ -13,10 +14,13 @@ static class SocketExtensions /// /// Attempt to exclusively bind to a given . /// + /// The to use. /// The port number to bind to. /// If IPV6 should be tested as well. - public static void BindTest(ushort port, bool includeIPv6) - => ProcessExecutor.WithProcessLaunchExclusivity(() => + public static void BindTest(IPlatformIdentifier platformIdentifier, ushort port, bool includeIPv6) + { + ArgumentNullException.ThrowIfNull(platformIdentifier); + ProcessExecutor.WithProcessLaunchExclusivity(() => { using var socket = new Socket( includeIPv6 @@ -27,7 +31,9 @@ public static void BindTest(ushort port, bool includeIPv6) socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); + if (platformIdentifier.IsWindows) + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); + if (includeIPv6) socket.DualMode = true; @@ -38,5 +44,6 @@ public static void BindTest(ushort port, bool includeIPv6) : IPAddress.Any, port)); }); + } } } diff --git a/src/Tgstation.Server.Host/Utils/PortAllocator.cs b/src/Tgstation.Server.Host/Utils/PortAllocator.cs index c2337135bc9..cf53aabe11a 100644 --- a/src/Tgstation.Server.Host/Utils/PortAllocator.cs +++ b/src/Tgstation.Server.Host/Utils/PortAllocator.cs @@ -12,6 +12,7 @@ using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Extensions; +using Tgstation.Server.Host.System; namespace Tgstation.Server.Host.Utils { @@ -28,6 +29,11 @@ sealed class PortAllocator : IPortAllocator /// readonly IDatabaseContext databaseContext; + /// + /// The for the . + /// + readonly IPlatformIdentifier platformIdentifier; + /// /// The for the . /// @@ -43,16 +49,19 @@ sealed class PortAllocator : IPortAllocator /// /// The value of . /// The value of . + /// The value of . /// The containing the value of . /// The value of . public PortAllocator( IServerPortProvider serverPortProvider, IDatabaseContext databaseContext, + IPlatformIdentifier platformIdentifier, IOptions swarmConfigurationOptions, ILogger logger) { this.serverPortProvider = serverPortProvider ?? throw new ArgumentNullException(nameof(serverPortProvider)); this.databaseContext = databaseContext ?? throw new ArgumentNullException(nameof(databaseContext)); + this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); swarmConfiguration = swarmConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(swarmConfigurationOptions)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); } @@ -92,7 +101,7 @@ public PortAllocator( try { - SocketExtensions.BindTest(port, false); + SocketExtensions.BindTest(platformIdentifier, port, false); } catch (Exception ex) { diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index ba69db8069b..bde4f326586 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -636,7 +636,7 @@ async Task StartDD(CancellationToken cancellationToken) { try { - SocketExtensions.BindTest(ddPort, false); + SocketExtensions.BindTest(new PlatformIdentifier(), ddPort, false); break; } catch From 5608b93ac175e602d897d469bc29631b5c0c3868 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 11:45:06 -0400 Subject: [PATCH 122/717] Fix various CI test issues --- .../Live/DummyChatProvider.cs | 7 +++--- .../Live/Instance/EngineTest.cs | 25 ++++++++++++++----- .../Live/TestLiveServer.cs | 3 +++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs index 88fba0b8bf1..411cfbc45cf 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs @@ -53,10 +53,11 @@ static IAsyncDelayer CreateMockDelayer() mock.Setup(x => x.Delay(It.IsAny(), It.IsAny())).Returns((delay, cancellationToken) => Task.Delay(TimeSpan.FromSeconds(3), cancellationToken)); return mock.Object; } - public static async Task RandomDisconnections(bool enabled, CancellationToken cancellationToken) + + public static Task RandomDisconnections(bool enabled, CancellationToken cancellationToken) { - if (Interlocked.Exchange(ref enableRandomDisconnections, enabled ? 1 : 0) != 0 && !enabled) - await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken); + // we just don't do random disconnections when live testing these days, too many potential issue vectors like thread exhaustion on actions runners + return Task.CompletedTask; } public DummyChatProvider( diff --git a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs index 6ca6ac32fbf..77fe29fa019 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs @@ -123,6 +123,19 @@ ValueTask TestInstallNullVersion(CancellationToken cancellationToken) cancellationToken), ErrorCode.ModelValidationFailure); + int EngineInstallationTimeout() + { + switch (testVersion.Engine.Value) + { + case EngineType.Byond: + return 30; + case EngineType.OpenDream: + return 300; + default: + throw new InvalidOperationException($"Unknown engine type: {testVersion.Engine.Value}"); + } + } + async Task RunContinued(Task firstInstall, CancellationToken cancellationToken) { await firstInstall; @@ -142,7 +155,7 @@ async Task TestDeletes(CancellationToken cancellationToken) CustomIteration = 2, } }, cancellationToken); - await WaitForJob(deleteThisOneBecauseItWasntPartOfTheOriginalTest, 30, false, null, cancellationToken); + await WaitForJob(deleteThisOneBecauseItWasntPartOfTheOriginalTest, EngineInstallationTimeout(), false, null, cancellationToken); var nonExistentUninstallResponseTask = ApiAssert.ThrowsException(() => engineClient.DeleteVersion( new EngineVersionDeleteRequest @@ -186,7 +199,7 @@ async Task TestDeletes(CancellationToken cancellationToken) Assert.IsNotNull(uninstallJob); // Has to wait on deployment test possibly - var uninstallTask = WaitForJob(uninstallJob, 120, false, null, cancellationToken); + var uninstallTask = WaitForJob(uninstallJob, EngineInstallationTimeout() + 90, false, null, cancellationToken); await nonExistentUninstallResponseTask; @@ -217,7 +230,7 @@ async Task TestInstallFakeVersion(CancellationToken cancellationToken) var test = await engineClient.SetActiveVersion(newModel, null, cancellationToken); Assert.IsNotNull(test.InstallJob); - await WaitForJob(test.InstallJob, 60, true, ErrorCode.EngineDownloadFail, cancellationToken); + await WaitForJob(test.InstallJob, EngineInstallationTimeout() + 30, true, ErrorCode.EngineDownloadFail, cancellationToken); } async Task TestInstallStable(CancellationToken cancellationToken) @@ -233,7 +246,7 @@ async Task TestInstallStable(CancellationToken cancellationToken) }; var test = await engineClient.SetActiveVersion(newModel, null, cancellationToken); Assert.IsNotNull(test.InstallJob); - await WaitForJob(test.InstallJob, 180, false, null, cancellationToken); + await WaitForJob(test.InstallJob, EngineInstallationTimeout() + 150, false, null, cancellationToken); var currentShit = await engineClient.ActiveVersion(cancellationToken); Assert.AreEqual(newModel.EngineVersion, currentShit.EngineVersion); Assert.IsFalse(currentShit.EngineVersion.CustomIteration.HasValue); @@ -304,7 +317,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) cancellationToken); Assert.IsNotNull(test.InstallJob); - await WaitForJob(test.InstallJob, 30, false, null, cancellationToken); + await WaitForJob(test.InstallJob, EngineInstallationTimeout(), false, null, cancellationToken); // do it again. #1501 stableBytesMs.Seek(0, SeekOrigin.Begin); @@ -324,7 +337,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) cancellationToken); Assert.IsNotNull(test2.InstallJob); - await WaitForJob(test2.InstallJob, 30, false, null, cancellationToken); + await WaitForJob(test2.InstallJob, EngineInstallationTimeout(), false, null, cancellationToken); var newSettings = await engineClient.ActiveVersion(cancellationToken); Assert.AreEqual(new Version(testVersion.Version.Major, testVersion.Version.Minor, 0), newSettings.EngineVersion.Version); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 0b576de6d70..cc9da38bddc 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1096,6 +1096,9 @@ async Task TestTgsInternal(CancellationToken hardCancellationToken) using var serverCts = CancellationTokenSource.CreateLinkedTokenSource(hardCancellationToken); var cancellationToken = serverCts.Token; + for (var i = 0; i < 50; ++i) + await Task.Yield(); + InstanceManager GetInstanceManager() => ((Host.Server)server.RealServer).Host.Services.GetRequiredService(); // main run From 25c997d64727b68d55fcb942d78c295a8034d76b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 11:55:22 -0400 Subject: [PATCH 123/717] Add OpenDream build step to CI Fix all usages of setup-dotnet --- .github/workflows/ci-pipeline.yml | 76 +++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 171a10eeabd..3470bd82096 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -164,6 +164,50 @@ jobs: fi exit $retval + opendream-build: + name: Build DMAPI (OpenDream) + needs: start-ci-run-gate + if: (!(cancelled() || failure()) && needs.start-ci-run-gate.result == 'success') + strategy: + fail-fast: false + matrix: + committish: [ 'master' ] + runs-on: ubuntu-latest + steps: + - name: Setup dotnet + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} + + - name: Checkout (Branch) + uses: actions/checkout@v3 + if: github.event_name == 'push' || github.event_name == 'schedule' + + - name: Checkout (PR Merge) + uses: actions/checkout@v3 + if: github.event_name != 'push' && github.event_name != 'schedule' + with: + ref: "refs/pull/${{ github.event.number }}/merge" + + - name: Checkout OpenDream + run: | + cd $HOME + git clone https://github.com/OpenDreamProject/OpenDream + cd OpenDream + git submodule init --update --recursive + git checkout ${{ matrix.committish }} + + - name: Build OpenDream + run: | + cd $HOME/OpenDream + dotnet build -c Release + + - name: Build OpenDream + run: | + cd tests/DMAPI/BasicOperation + $HOME/OpenDream/bin/DMCompiler/DMCompiler --verbose --notices-enabled basic_operation_test.dme + pages-build: name: Build gh-pages runs-on: ubuntu-latest @@ -173,7 +217,8 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v3 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout (Branch) uses: actions/checkout@v3 @@ -275,6 +320,7 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout (Branch) uses: actions/checkout@v3 @@ -325,6 +371,7 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout (Branch) uses: actions/checkout@v3 @@ -360,8 +407,8 @@ jobs: windows-integration-test: name: Windows Live Tests - needs: dmapi-build - if: (!(cancelled() || failure()) && needs.dmapi-build.result == 'success') + needs: [dmapi-build, opendream-build] + if: (!(cancelled() || failure()) && needs.dmapi-build.result == 'success' && needs.opendream-build.result == 'success') strategy: fail-fast: false matrix: @@ -381,6 +428,7 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Set TGS_TEST_DUMP_API_SPEC if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'System' && matrix.database-type == 'SqlServer' }} @@ -516,8 +564,8 @@ jobs: linux-integration-tests: name: Linux Live Tests - needs: dmapi-build - if: (!(cancelled() || failure()) && needs.dmapi-build.result == 'success') + needs: [dmapi-build, opendream-build] + if: (!(cancelled() || failure()) && needs.dmapi-build.result == 'success' && needs.opendream-build.result == 'success') services: # We start all dbs here so we can just code the stuff once mssql: image: mcr.microsoft.com/mssql/server:2019-latest @@ -580,6 +628,7 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Set Sqlite Connection Info if: ${{ matrix.database-type == 'Sqlite' }} @@ -1083,6 +1132,7 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout (Branch) uses: actions/checkout@v3 @@ -1208,6 +1258,7 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Retrieve Latest winget-pkgs PULL_REQUEST_TEMPLATE commit SHA from GitHub API id: get-sha @@ -1261,7 +1312,8 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v3 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout uses: actions/checkout@v3 @@ -1324,7 +1376,8 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v3 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout uses: actions/checkout@v3 @@ -1387,6 +1440,7 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout uses: actions/checkout@v3 @@ -1437,6 +1491,7 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout uses: actions/checkout@v3 @@ -1460,6 +1515,7 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout uses: actions/checkout@v3 @@ -1656,9 +1712,10 @@ jobs: if: (!(cancelled() || failure()) && needs.deploy-tgs.result == 'success') steps: - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: ${{ env.TGS_DOTNET_VERSION }} + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout uses: actions/checkout@v3 @@ -1746,6 +1803,7 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Install winget uses: Cyberboss/install-winget@v1 From 2747b91a2dbe18d1590d3e0880684812d266587c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 11:58:23 -0400 Subject: [PATCH 124/717] Fix DMAPI build OD submodule update Checkout before initialization --- .github/workflows/ci-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 3470bd82096..8c0c9c06617 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -195,8 +195,8 @@ jobs: cd $HOME git clone https://github.com/OpenDreamProject/OpenDream cd OpenDream - git submodule init --update --recursive git checkout ${{ matrix.committish }} + git submodule update --init --recursive - name: Build OpenDream run: | From 97e4ad2dc5e1142148f5eec427292345c18c9238 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 12:36:28 -0400 Subject: [PATCH 125/717] Fix `General:OpenDreamGitUrl` serialization --- .../Configuration/GeneralConfiguration.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs index eecca9cd9ff..0ef30ddac5b 100644 --- a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs @@ -9,6 +9,8 @@ using Tgstation.Server.Host.Properties; using Tgstation.Server.Host.Setup; +using YamlDotNet.Serialization; + namespace Tgstation.Server.Host.Configuration { /// @@ -135,6 +137,7 @@ public sealed class GeneralConfiguration : ServerInformationBase /// /// Location of a publically accessible OpenDream repository. /// + [YamlMember(SerializeAs = typeof(string))] public Uri OpenDreamGitUrl { get; set; } = new Uri(DefaultOpenDreamGitUrl); /// From 4599e462b2b075c151283cae3d927f0c65ebe93e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 12:36:50 -0400 Subject: [PATCH 126/717] Fix test timeouts for OpenDream installation --- tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs | 5 +++-- tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs | 2 +- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs index 77fe29fa019..d03ad60dba0 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs @@ -122,8 +122,7 @@ ValueTask TestInstallNullVersion(CancellationToken cancellationToken) null, cancellationToken), ErrorCode.ModelValidationFailure); - - int EngineInstallationTimeout() + public static int EngineInstallationTimeout(EngineVersion testVersion) { switch (testVersion.Engine.Value) { @@ -136,6 +135,8 @@ int EngineInstallationTimeout() } } + int EngineInstallationTimeout() => EngineInstallationTimeout(testVersion); + async Task RunContinued(Task firstInstall, CancellationToken cancellationToken) { await firstInstall; diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 26f00486bd7..c674a3a42d0 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -210,7 +210,7 @@ public async Task RunCompatTests( var theJobWeWant = jobs.First(x => x.Description.Contains("Reconnect chat bot")); await Task.WhenAll( - jrt.WaitForJob(installJob2.InstallJob, 60, false, null, cancellationToken), + jrt.WaitForJob(installJob2.InstallJob, EngineTest.EngineInstallationTimeout(compatVersion) + 30, false, null, cancellationToken), jrt.WaitForJob(cloneRequest.Result.ActiveJob, 60, false, null, cancellationToken), jrt.WaitForJob(theJobWeWant, 30, false, null, cancellationToken), dmUpdateRequest.AsTask(), diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index bde4f326586..26dd4a326ea 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -1042,7 +1042,7 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken // This used to be the case but it gets deleted now that we have and test that // Assert.IsNull(byondInstallJob.InstallJob); - await WaitForJob(byondInstallJob.InstallJob, 60, false, null, cancellationToken); + await WaitForJob(byondInstallJob.InstallJob, EngineTest.EngineInstallationTimeout(versionToInstall) + 30, false, null, cancellationToken); const string DmeName = "LongRunning/long_running_test"; From 8d1cef756358d5f5b0cca674de9018f9ed7272d0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 16 Oct 2023 12:37:13 -0400 Subject: [PATCH 127/717] Correct CI step name --- .github/workflows/ci-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 8c0c9c06617..0d8c6688701 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -203,7 +203,7 @@ jobs: cd $HOME/OpenDream dotnet build -c Release - - name: Build OpenDream + - name: Build DMAPI run: | cd tests/DMAPI/BasicOperation $HOME/OpenDream/bin/DMCompiler/DMCompiler --verbose --notices-enabled basic_operation_test.dme From 7bebd915df5fdc22bc19a49e21ad7a79c264590c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 10 Oct 2023 19:18:49 -0400 Subject: [PATCH 128/717] Update to .NET 8 RC2 --- build/Version.props | 2 +- .../Tgstation.Server.Host.Console.csproj | 2 +- .../Tgstation.Server.Host.Service.csproj | 8 +++---- .../Tgstation.Server.Host.Watchdog.csproj | 2 +- .../.config/dotnet-tools.json | 2 +- .../Tgstation.Server.Host.csproj | 22 +++++++++---------- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/build/Version.props b/build/Version.props index 782ee29423f..ab8fe0760b1 100644 --- a/build/Version.props +++ b/build/Version.props @@ -17,7 +17,7 @@ netstandard2.0 8 - https://download.visualstudio.microsoft.com/download/pr/f6fcf7ad-2ae2-4b26-97be-bfaff4e6d873/4005d9603269b7266bd156ad1393475c/dotnet-hosting-8.0.0-rc.1.23421.29-win.exe + https://download.visualstudio.microsoft.com/download/pr/f0a627b7-bd46-4ed2-978d-00a445174074/182420f488062f1983fc392b2fb66967/dotnet-hosting-8.0.0-rc.2.23480.2-win.exe 10.11.5 https://ftp.osuosl.org/pub/mariadb//mariadb-10.11.5/winx64-packages/mariadb-10.11.5-winx64.msi 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 4ff44fedb75..89392d1fb6d 100644 --- a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj +++ b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj @@ -11,7 +11,7 @@ - + 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 c9f9666e184..a7c6d3c406a 100644 --- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj +++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj @@ -19,15 +19,15 @@ - + - + - + - + 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 da8207e6a85..5428b3b8488 100644 --- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj +++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Tgstation.Server.Host/.config/dotnet-tools.json b/src/Tgstation.Server.Host/.config/dotnet-tools.json index 2013d181bd4..7bf21904659 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.0-rc.1.23419.6", + "version": "8.0.0-rc.2.23479.6", "commands": [ "dotnet-ef" ] diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 47ea588eaf7..6696452c934 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -75,25 +75,25 @@ - + - + - + - + runtime; build; native; contentfiles; analyzers; buildtransitive - + - + - + @@ -115,13 +115,13 @@ - + - + - + - + From 96222d80e4216d8df4f98e865eb180fc3942fcba Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 20 Oct 2023 16:42:08 -0400 Subject: [PATCH 129/717] Switch to new packager --- .../Components/Engine/OpenDreamInstaller.cs | 89 +++++++------------ 1 file changed, 30 insertions(+), 59 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 81734db3d51..1e6f89226a3 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -31,7 +31,7 @@ class OpenDreamInstaller : EngineInstallerBase /// /// The OD server directory name. /// - const string ServerDir = "Content.Server"; + const string ServerDir = "server"; /// /// The name of the subdirectory in an installation's used to store the compiler binaries. @@ -216,15 +216,16 @@ public override async ValueTask Install(EngineVersion version, string installPat var dotnetPath = dotnetPaths[selectedPathIndex]; - // TODO: https://github.com/OpenDreamProject/OpenDream/issues/1495 + const string DeployDir = "tgs_deploy"; int? buildExitCode = null; await HandleExtremelyLongPathOperation( async shortenedPath => { + var shortenedDeployPath = IOManager.ConcatPath(shortenedPath, DeployDir); await using var buildProcess = ProcessExecutor.LaunchProcess( dotnetPath, shortenedPath, - "build -c Release /p:TgsEngineBuild=true", + $"run -c Release --project OpenDreamPackageTool -- --tgs -o {shortenedDeployPath}", null, true, true); @@ -241,68 +242,38 @@ await HandleExtremelyLongPathOperation( if (buildExitCode != 0) throw new JobException("OpenDream build failed!"); - async ValueTask MoveBinFiles() + var deployPath = IOManager.ConcatPath(sourcePath, DeployDir); + async ValueTask MoveDirs() { - var installBinPath = IOManager.ConcatPath(installPath, BinDir); - - await IOManager.CreateDirectory(installBinPath, cancellationToken); - - var serverMoveTask = IOManager.MoveDirectory( - IOManager.ConcatPath( - sourcePath, - BinDir, - ServerDir), - IOManager.ConcatPath( - installBinPath, - ServerDir), - cancellationToken); - - var compilerMoveTask = IOManager.MoveDirectory( - IOManager.ConcatPath( - sourcePath, - BinDir, - "DMCompiler"), - IOManager.ConcatPath( - installBinPath, - InstallationCompilerDirectory), - cancellationToken); - - await Task.WhenAll(serverMoveTask, compilerMoveTask); + var dirs = await IOManager.GetDirectories(deployPath, cancellationToken); + await Task.WhenAll( + dirs.Select( + dir => IOManager.MoveDirectory( + IOManager.ConcatPath( + deployPath, + dir), + IOManager.ConcatPath( + installPath, + dir), + cancellationToken))); } - async ValueTask MoveResources() + async ValueTask MoveFiles() { - const string RobustDir = "RobustToolbox"; - const string ResourcesDir = "Resources"; - - var rootMoveTask = IOManager.MoveDirectory( - IOManager.ConcatPath( - sourcePath, - ResourcesDir), - IOManager.ConcatPath( - installPath, - ResourcesDir), - cancellationToken); - var installRobustDir = IOManager.ConcatPath(installPath, RobustDir); - - await IOManager.CreateDirectory(installRobustDir, cancellationToken); - var robustMoveTask = IOManager.MoveDirectory( - IOManager.ConcatPath( - sourcePath, - RobustDir, - ResourcesDir), - IOManager.ConcatPath( - installRobustDir, - ResourcesDir), - cancellationToken); - - await Task.WhenAll(rootMoveTask, robustMoveTask); + var files = await IOManager.GetFiles(deployPath, cancellationToken); + await Task.WhenAll( + files.Select( + file => IOManager.MoveFile( + IOManager.ConcatPath( + deployPath, + file), + IOManager.ConcatPath( + installPath, + file), + cancellationToken))); } - var binSetupTask = MoveBinFiles(); - var resourcesMoveTask = MoveResources(); - - await ValueTaskExtensions.WhenAll(binSetupTask, resourcesMoveTask); + await ValueTaskExtensions.WhenAll(MoveDirs(), MoveFiles()); await IOManager.DeleteDirectory(sourcePath, cancellationToken); } From a2b4d97335a38cba80ee9fcc3a524b2a4f8bb00d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 00:51:07 -0400 Subject: [PATCH 130/717] Fix IIOManager documentation comments --- src/Tgstation.Server.Host/IO/IIOManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/IIOManager.cs b/src/Tgstation.Server.Host/IO/IIOManager.cs index 045036e98cc..0b249b23a24 100644 --- a/src/Tgstation.Server.Host/IO/IIOManager.cs +++ b/src/Tgstation.Server.Host/IO/IIOManager.cs @@ -88,7 +88,7 @@ ValueTask CopyDirectory( ValueTask ReadAllBytes(string path, CancellationToken cancellationToken); /// - /// Returns directory names in a given . + /// Returns full directory names in a given . /// /// The path to search for directories. /// The for the operation. @@ -96,7 +96,7 @@ ValueTask CopyDirectory( Task> GetDirectories(string path, CancellationToken cancellationToken); /// - /// Returns file names in a given . + /// Returns full file names in a given . /// /// The path to search for files. /// The for the operation. From 24e21f6c3ec3021de4c3023dd9b5fb5723d4ed60 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 00:51:23 -0400 Subject: [PATCH 131/717] Fix OD engine installation --- .../Components/Engine/OpenDreamInstaller.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 1e6f89226a3..6aa5e728fbe 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -249,12 +249,10 @@ async ValueTask MoveDirs() await Task.WhenAll( dirs.Select( dir => IOManager.MoveDirectory( - IOManager.ConcatPath( - deployPath, - dir), + dir, IOManager.ConcatPath( installPath, - dir), + IOManager.GetFileName(dir)), cancellationToken))); } @@ -264,12 +262,10 @@ async ValueTask MoveFiles() await Task.WhenAll( files.Select( file => IOManager.MoveFile( - IOManager.ConcatPath( - deployPath, - file), + file, IOManager.ConcatPath( installPath, - file), + IOManager.GetFileName(file)), cancellationToken))); } @@ -321,7 +317,7 @@ protected void GetExecutablePaths(string installationPath, out string serverExeP installationPath, BinDir, ServerDir, - $"OpenDreamServer{exeExtension}"); + $"Robust.Server{exeExtension}"); compilerExePath = IOManager.ConcatPath( installationPath, From 45f5f7456a44868172c434abd7ff4cc8eae1ad1a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 01:10:02 -0400 Subject: [PATCH 132/717] Remove some unused usings --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 961b8fed3e3..16900200519 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -8,7 +8,6 @@ using Newtonsoft.Json; using System; -using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; @@ -25,7 +24,6 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client; using Tgstation.Server.Client.Components; -using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Interop; From 61278a876f8902f53a1a151e1a0e19f1432fdc45 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 01:30:43 -0400 Subject: [PATCH 133/717] Rename `byondLock` variables to `engineLock` --- .../Components/Deployment/DreamMaker.cs | 16 ++++----- .../Session/SessionControllerFactory.cs | 34 +++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index 800929493d1..cc142b8ce03 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -477,10 +477,10 @@ await databaseContextFactory.UseContext( var progressTask = ProgressTask(progressReporter, estimatedDuration, progressCts.Token); try { - using var byondLock = await engineManager.UseExecutables(null, null, cancellationToken); + using var engineLock = await engineManager.UseExecutables(null, null, cancellationToken); currentChatCallback = chatManager.QueueDeploymentMessage( revisionInformation, - byondLock.Version, + engineLock.Version, DateTimeOffset.UtcNow + estimatedDuration, repository.RemoteRepositoryOwner, repository.RemoteRepositoryName, @@ -491,7 +491,7 @@ await databaseContextFactory.UseContext( DirectoryName = Guid.NewGuid(), DmeName = dreamMakerSettings.ProjectName, RevisionInformation = revisionInformation, - ByondVersion = byondLock.Version.ToString(), + ByondVersion = engineLock.Version.ToString(), RepositoryOrigin = repository.Origin.ToString(), }; @@ -514,7 +514,7 @@ await RunCompileJob( job, dreamMakerSettings, launchParameters, - byondLock, + engineLock, repository, remoteDeploymentManager, combinedTokenSource.Token); @@ -764,7 +764,7 @@ async ValueTask ProgressTask(JobProgressReporter progressReporter, TimeSpan? est /// The timeout in seconds for validation. /// The level to use to validate the API. /// The for the operation. - /// The current . + /// The current . /// The port to use for API validation. /// If the API validation is required to complete the deployment. /// If output should be logged to the DreamDaemon Diagnostics folder. @@ -774,7 +774,7 @@ async ValueTask VerifyApi( uint timeout, DreamDaemonSecurity securityLevel, Models.CompileJob job, - IEngineExecutableLock byondLock, + IEngineExecutableLock engineLock, ushort portToUse, bool requireValidate, bool logOutput, @@ -801,8 +801,8 @@ async ValueTask VerifyApi( using (var provider = new TemporaryDmbProvider( ioManager.ResolvePath(job.DirectoryName.ToString()), job, - byondLock.Version)) - await using (var controller = await sessionControllerFactory.LaunchNew(provider, byondLock, launchParameters, true, cancellationToken)) + engineLock.Version)) + await using (var controller = await sessionControllerFactory.LaunchNew(provider, engineLock, launchParameters, true, cancellationToken)) { var launchResult = await controller.LaunchResult.WaitAsync(cancellationToken); diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 96f28e042e5..bf845fb6078 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -240,7 +240,7 @@ public async ValueTask LaunchNew( } // get the byond lock - var byondLock = currentByondLock ?? await engineManager.UseExecutables( + var engineLock = currentByondLock ?? await engineManager.UseExecutables( dmbProvider.EngineVersion, gameIOManager.ConcatPath(dmbProvider.Directory, dmbProvider.DmbName), cancellationToken); @@ -260,7 +260,7 @@ public async ValueTask LaunchNew( string outputFilePath = null; var preserveLogFile = true; - var hasStandardOutput = byondLock.HasStandardOutput; + var hasStandardOutput = engineLock.HasStandardOutput; if (launchParameters.LogOutput.Value) { var now = DateTimeOffset.UtcNow; @@ -287,7 +287,7 @@ public async ValueTask LaunchNew( // launch dd var process = await CreateGameServerProcess( dmbProvider, - byondLock, + engineLock, launchParameters, accessIdentifier, outputFilePath, @@ -321,7 +321,7 @@ public async ValueTask LaunchNew( reattachInformation, instance, process, - byondLock, + engineLock, byondTopicSender, chatTrackingContext, bridgeRegistrar, @@ -360,7 +360,7 @@ public async ValueTask LaunchNew( catch { if (currentByondLock == null) - byondLock.Dispose(); + engineLock.Dispose(); throw; } } @@ -375,7 +375,7 @@ public async ValueTask Reattach( logger.LogTrace("Begin session reattach..."); var byondTopicSender = topicClientFactory.CreateTopicClient(reattachInformation.TopicRequestTimeout); - var byondLock = await engineManager.UseExecutables( + var engineLock = await engineManager.UseExecutables( reattachInformation.Dmb.EngineVersion, null, // Doesn't matter if it's trusted or not on reattach cancellationToken); @@ -393,7 +393,7 @@ public async ValueTask Reattach( try { - if (byondLock.PromptsForNetworkAccess) + if (engineLock.PromptsForNetworkAccess) networkPromptReaper.RegisterProcess(process); var chatTrackingContext = chat.CreateTrackingContext(); @@ -410,7 +410,7 @@ public async ValueTask Reattach( reattachInformation, instance, process, - byondLock, + engineLock, byondTopicSender, chatTrackingContext, bridgeRegistrar, @@ -424,7 +424,7 @@ public async ValueTask Reattach( false); process = null; - byondLock = null; + engineLock = null; chatTrackingContext = null; return controller; @@ -443,7 +443,7 @@ public async ValueTask Reattach( } catch { - byondLock.Dispose(); + engineLock.Dispose(); throw; } } @@ -452,7 +452,7 @@ public async ValueTask Reattach( /// Creates the game server . /// /// The . - /// The . + /// The . /// The . /// The secure string to use for the session. /// The path to log DreamDaemon output to. @@ -461,7 +461,7 @@ public async ValueTask Reattach( /// A resulting in the DreamDaemon . async ValueTask CreateGameServerProcess( IDmbProvider dmbProvider, - IEngineExecutableLock byondLock, + IEngineExecutableLock engineLock, DreamDaemonLaunchParameters launchParameters, string accessIdentifier, string logFilePath, @@ -469,7 +469,7 @@ async ValueTask CreateGameServerProcess( CancellationToken cancellationToken) { // important to run on all ports to allow port changing - var arguments = byondLock.FormatServerArguments( + var arguments = engineLock.FormatServerArguments( dmbProvider, new Dictionary { @@ -478,16 +478,16 @@ async ValueTask CreateGameServerProcess( { DMApiConstants.ParamAccessIdentifier, accessIdentifier }, }, launchParameters, - !byondLock.HasStandardOutput + !engineLock.HasStandardOutput ? logFilePath : null); var process = processExecutor.LaunchProcess( - byondLock.ServerExePath, + engineLock.ServerExePath, dmbProvider.Directory, arguments, logFilePath, - byondLock.HasStandardOutput, + engineLock.HasStandardOutput, true); try @@ -500,7 +500,7 @@ async ValueTask CreateGameServerProcess( else if (sessionConfiguration.LowPriorityDeploymentProcesses) process.AdjustPriority(false); - if (!byondLock.HasStandardOutput) + if (!engineLock.HasStandardOutput) networkPromptReaper.RegisterProcess(process); // If this isnt a staging DD (From a Deployment), fire off an event From 1480e48e5414d56237bdb24ce983623c9b800d7a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 03:40:39 -0400 Subject: [PATCH 134/717] Take advantage of Robust's logging cvars - Finally add port test retries for up to 5s. - Fix weirdness with logging to file vs reading std handles. - Replace some "DD" references with "server" --- .../Components/Engine/ByondInstallation.cs | 3 ++ .../Components/Engine/EngineExecutableLock.cs | 3 ++ .../Engine/EngineInstallationBase.cs | 3 ++ .../Components/Engine/IEngineInstallation.cs | 5 +++ .../Engine/OpenDreamInstallation.cs | 9 +++-- .../Session/SessionControllerFactory.cs | 40 ++++++++++++++----- .../Live/TestLiveServer.cs | 2 +- 7 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs index 345ee5e743b..ba730a7c7fa 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs @@ -29,6 +29,9 @@ sealed class ByondInstallation : EngineInstallationBase /// public override bool HasStandardOutput { get; } + /// + public override bool PreferFileLogging => false; + /// public override Task InstallationTask { get; } diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs index 6ef921aaa73..77c40caed9b 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs @@ -22,6 +22,9 @@ sealed class EngineExecutableLock : ReferenceCounter, IEngi /// public bool HasStandardOutput => Instance.HasStandardOutput; + /// + public bool PreferFileLogging => Instance.PreferFileLogging; + /// public bool PromptsForNetworkAccess => Instance.PromptsForNetworkAccess; diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs index 8bd53be358d..d8cc5f64ea3 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs @@ -24,6 +24,9 @@ abstract class EngineInstallationBase : IEngineInstallation /// public abstract bool HasStandardOutput { get; } + /// + public abstract bool PreferFileLogging { get; } + /// public abstract bool PromptsForNetworkAccess { get; } diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs index aa43847ae2d..1fc6c4ad7b5 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs @@ -36,6 +36,11 @@ public interface IEngineInstallation /// bool PromptsForNetworkAccess { get; } + /// + /// If is set, this indicates that the engine server has good file logging that should be preferred to ours. + /// + bool PreferFileLogging { get; } + /// /// The that completes when the BYOND version finished installing. /// diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index e6413570f16..2840db98eb2 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -28,6 +28,9 @@ sealed class OpenDreamInstallation : EngineInstallationBase /// public override bool HasStandardOutput => true; + /// + public override bool PreferFileLogging => true; + /// public override Task InstallationTask { get; } @@ -64,12 +67,10 @@ public override string FormatServerArguments( ArgumentNullException.ThrowIfNull(parameters); ArgumentNullException.ThrowIfNull(launchParameters); - if (logFilePath != null) - throw new NotSupportedException("OpenDream does not support logging to a file!"); - var parametersString = EncodeParameters(parameters, launchParameters); - var arguments = $"--cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" \"{dmbProvider.DmbName}\""; + var loggingEnabled = logFilePath != null; + var arguments = $"--cvar {(loggingEnabled ? $"log.path=\"{logFilePath}\"" : "log.enabled=false")} --cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" \"{dmbProvider.DmbName}\""; return arguments; } diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index bf845fb6078..43d5d3f684a 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -130,12 +130,28 @@ sealed class SessionControllerFactory : ISessionControllerFactory /// Check if a given can be bound to. /// /// The port number to test. - void PortBindTest(ushort port) + /// The for the operation. + /// A representing the running operation. + async ValueTask PortBindTest(ushort port, CancellationToken cancellationToken) { + logger.LogTrace("Bind test: {port}", port); try { - logger.LogTrace("Bind test: {port}", port); - SocketExtensions.BindTest(platformIdentifier, port, false); + // GIVE ME THE FUCKING PORT BACK WINDOWS!!!! + const int MaxAttempts = 5; + for (var i = 0; i < MaxAttempts; ++i) + try + { + SocketExtensions.BindTest(platformIdentifier, port, false); + if (i > 0) + logger.LogDebug("Clearing the socket took {iterations} attempts :/", i + 1); + + break; + } + catch (SocketException ex) when (platformIdentifier.IsWindows && ex.SocketErrorCode == SocketError.AddressAlreadyInUse && i < (MaxAttempts - 1)) + { + await asyncDelayer.Delay(TimeSpan.FromSeconds(1), cancellationToken); + } } catch (SocketException ex) when (ex.SocketErrorCode == SocketError.AddressAlreadyInUse) { @@ -255,7 +271,7 @@ public async ValueTask LaunchNew( if (engineType == EngineType.Byond) await CheckPagerIsNotRunning(); - PortBindTest(launchParameters.Port.Value); + await PortBindTest(launchParameters.Port.Value, cancellationToken); string outputFilePath = null; var preserveLogFile = true; @@ -269,13 +285,13 @@ public async ValueTask LaunchNew( outputFilePath = diagnosticsIOManager.ResolvePath( diagnosticsIOManager.ConcatPath( dateDirectory, - $"dd-utc-{now.ToString("yyyy-MM-dd-HH-mm-ss", CultureInfo.InvariantCulture)}{(apiValidate ? "-dmapi" : String.Empty)}.log")); + $"server-utc-{now.ToString("yyyy-MM-dd-HH-mm-ss", CultureInfo.InvariantCulture)}{(apiValidate ? "-dmapi" : String.Empty)}.log")); - logger.LogInformation("Logging DreamDaemon output to {path}...", outputFilePath); + logger.LogInformation("Logging server output to {path}...", outputFilePath); } else if (!hasStandardOutput) { - outputFilePath = gameIOManager.ConcatPath(dmbProvider.Directory, $"{Guid.NewGuid()}.dd.log"); + outputFilePath = gameIOManager.ConcatPath(dmbProvider.Directory, $"{Guid.NewGuid()}.server.log"); preserveLogFile = false; } @@ -478,7 +494,7 @@ async ValueTask CreateGameServerProcess( { DMApiConstants.ParamAccessIdentifier, accessIdentifier }, }, launchParameters, - !engineLock.HasStandardOutput + !engineLock.HasStandardOutput || engineLock.PreferFileLogging ? logFilePath : null); @@ -563,18 +579,20 @@ async ValueTask LogDDOutput(IProcess process, string outputFilePath, bool cliSup } catch (Exception ex) { - logger.LogWarning(ex, "Failed to delete DreamDaemon log file {outputFilePath}!", outputFilePath); + // this is expected on OD at time of the support changes. + // I've open a change to fix it: https://github.com/space-wizards/RobustToolbox/pull/4501 + logger.LogWarning(ex, "Failed to delete server log file {outputFilePath}!", outputFilePath); } } logger.LogTrace( - "DreamDaemon Output:{newLine}{output}", + "Server Output:{newLine}{output}", Environment.NewLine, ddOutput); } catch (Exception ex) { - logger.LogWarning(ex, "Error reading DreamDaemon output!"); + logger.LogWarning(ex, "Error reading server output!"); } } diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 04000d95466..6e5a48dc914 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -72,7 +72,7 @@ public sealed class TestLiveServer result.AddRange(System.Diagnostics.Process.GetProcessesByName("dd")); break; case EngineType.OpenDream: - result.AddRange(System.Diagnostics.Process.GetProcessesByName("OpenDreamServer")); + result.AddRange(System.Diagnostics.Process.GetProcessesByName("Robust.Server")); break; default: Assert.Fail($"Unknown engine type: {engineType}"); From c6b435c4d50fe30897763edc73f792615a7f4edb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 03:46:36 -0400 Subject: [PATCH 135/717] More engine generic deployment chat messages --- .../Components/Chat/Providers/DiscordProvider.cs | 9 +++++---- .../Components/Chat/Providers/IrcProvider.cs | 5 +++-- .../Components/Chat/Providers/Provider.cs | 13 +++++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 7737c33f3ac..a4be368ea22 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -322,9 +322,10 @@ public override async ValueTask(); + var prefix = GetEngineCompilerPrefix(engineVersion.Engine.Value); var messageResponse = await channelsClient.CreateMessageAsync( new Snowflake(channelId), - "DM: Deployment in progress...", + $"{prefix}: Deployment in progress...", embeds: new List { embed }, ct: cancellationToken); @@ -371,7 +372,7 @@ public override async ValueTask CancellationTokenSource reconnectCts; + /// + /// Get the prefix for messages about deployments. + /// + /// The of the deployment. + /// The prefix. + protected static string GetEngineCompilerPrefix(Api.Models.EngineType engineType) + => engineType switch + { + Api.Models.EngineType.Byond => "DM", + Api.Models.EngineType.OpenDream => "OD", + _ => throw new InvalidOperationException($"Unsupported engine type: {engineType}"), + }; + /// /// Initializes a new instance of the class. /// From d6881f65f7b9efb5dd6020745162923bffd46503 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 04:17:39 -0400 Subject: [PATCH 136/717] Correct i before e typos --- README.md | 2 +- docs/API.dox | 6 +++--- .../Models/Response/AdministrationResponse.cs | 2 +- .../Components/Chat/Providers/IProvider.cs | 2 +- .../Components/Chat/Providers/Message.cs | 2 +- src/Tgstation.Server.Host/Components/InstanceManager.cs | 2 +- .../Configuration/UpdatesConfiguration.cs | 2 +- src/Tgstation.Server.Host/Controllers/BridgeController.cs | 2 +- src/Tgstation.Server.Host/Controllers/SwarmController.cs | 2 +- src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs | 2 +- src/Tgstation.Server.Host/Swarm/SwarmService.cs | 2 +- tests/DMAPI/LongRunning/Test.dm | 4 ++-- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 4d6d1b192cd..e562d0f6158 100644 --- a/README.md +++ b/README.md @@ -383,7 +383,7 @@ Exposing the builtin Kestrel server to the internet directly over HTTP is highly System administrators will most likely have their own configuration plans, but here are some basic guides for beginners. -Once complete, test that your configuration worked by visiting your proxy site from a browser on a different computer. You should recieve a 401 Unauthorized response. +Once complete, test that your configuration worked by visiting your proxy site from a browser on a different computer. You should receive a 401 Unauthorized response. #### IIS (Reccommended for Windows) diff --git a/docs/API.dox b/docs/API.dox index a859e36c47e..f8ce9757f2c 100644 --- a/docs/API.dox +++ b/docs/API.dox @@ -115,13 +115,13 @@ If the provided credentials are valid and your user account is enabled you will } @endcode -If your account is disabled, you will recieve a 403 response. +If your account is disabled, you will receive a 403 response. You may recognize the bearer value as a Json Web Token. This is a secure representation of your identity to the server. It expires after a set period of time or until your password changes. It must be present for requests made to all other APIs. To do so add the following header to your other requests - Authorization:Bearer `` -Continue to use this token until you begin to recieve 401 responses from the API. Then repeat the process to get a new one if your credentials are still valid +Continue to use this token until you begin to receive 401 responses from the API. Then repeat the process to get a new one if your credentials are still valid @subsection api_auth_o OAuth 2.0 @@ -468,7 +468,7 @@ I POST "/Config" @ref Tgstation.Server.Api.Models.ConfigurationFile => @ref Tgst When creating a file, only @ref Tgstation.Server.Api.Models.ConfigurationFile.Path and @ref Tgstation.Server.Api.Models.ConfigurationFile.Content should be specified -If the file already exists, the @ref Tgstation.Server.Api.Models.ConfigurationFile.LastReadHash field must also be present with the last version recieved from the server for that file. If this does not match at the time of the request, 409 will be returned, indicating the file has changed since it was last viewed by the client. +If the file already exists, the @ref Tgstation.Server.Api.Models.ConfigurationFile.LastReadHash field must also be present with the last version received from the server for that file. If this does not match at the time of the request, 409 will be returned, indicating the file has changed since it was last viewed by the client. To delete a file set @ref Tgstation.Server.Api.Models.ConfigurationFile.Content to null in the request. diff --git a/src/Tgstation.Server.Api/Models/Response/AdministrationResponse.cs b/src/Tgstation.Server.Api/Models/Response/AdministrationResponse.cs index ab8ce0aba6b..55d7f646e5c 100644 --- a/src/Tgstation.Server.Api/Models/Response/AdministrationResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/AdministrationResponse.cs @@ -8,7 +8,7 @@ namespace Tgstation.Server.Api.Models.Response public sealed class AdministrationResponse { /// - /// The GitHub repository the server is built to recieve updates from. + /// The GitHub repository the server is built to receive updates from. /// public Uri? TrackedRepositoryUrl { get; set; } diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs index 710559c2777..109ec8a74c3 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs @@ -40,7 +40,7 @@ interface IProvider : IAsyncDisposable void InitialMappingComplete(); /// - /// Get a resulting in the next the recieves or on a disconnect. + /// Get a resulting in the next the receives or on a disconnect. /// /// The for the operation. /// A resulting in the next available or if the needed to reconnect. diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/Message.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/Message.cs index 321907029bd..9510113f62e 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/Message.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/Message.cs @@ -1,7 +1,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers { /// - /// Represents a message recieved by a . + /// Represents a message received by a . /// class Message { diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index e790294c090..aebd036f9bc 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -519,7 +519,7 @@ public async ValueTask ProcessBridgeRequest(BridgeParameters par lock (bridgeHandlers) if (!bridgeHandlers.TryGetValue(parameters.AccessIdentifier, out bridgeHandler)) { - logger.LogWarning("Recieved invalid bridge request with access identifier: {accessIdentifier}", parameters.AccessIdentifier); + logger.LogWarning("Received invalid bridge request with access identifier: {accessIdentifier}", parameters.AccessIdentifier); return null; } diff --git a/src/Tgstation.Server.Host/Configuration/UpdatesConfiguration.cs b/src/Tgstation.Server.Host/Configuration/UpdatesConfiguration.cs index 8f1a6d503e3..1e340c84caa 100644 --- a/src/Tgstation.Server.Host/Configuration/UpdatesConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/UpdatesConfiguration.cs @@ -28,7 +28,7 @@ public sealed class UpdatesConfiguration const string DefaultUpdatePackageAssetName = "ServerUpdatePackage.zip"; /// - /// The of the tgstation-server fork to recieve updates from. + /// The of the tgstation-server fork to receive updates from. /// public long GitHubRepositoryId { get; set; } = DefaultGitHubRepositoryId; diff --git a/src/Tgstation.Server.Host/Controllers/BridgeController.cs b/src/Tgstation.Server.Host/Controllers/BridgeController.cs index 1f53b43ec20..19c2794f04a 100644 --- a/src/Tgstation.Server.Host/Controllers/BridgeController.cs +++ b/src/Tgstation.Server.Host/Controllers/BridgeController.cs @@ -17,7 +17,7 @@ namespace Tgstation.Server.Host.Controllers { /// - /// for recieving DMAPI requests from DreamDaemon. + /// for receiving DMAPI requests from DreamDaemon. /// [Route("/Bridge")] [Produces(MediaTypeNames.Application.Json)] diff --git a/src/Tgstation.Server.Host/Controllers/SwarmController.cs b/src/Tgstation.Server.Host/Controllers/SwarmController.cs index 8b941d425c9..4829854ac5b 100644 --- a/src/Tgstation.Server.Host/Controllers/SwarmController.cs +++ b/src/Tgstation.Server.Host/Controllers/SwarmController.cs @@ -190,7 +190,7 @@ public async ValueTask CommitUpdate(CancellationToken cancellatio if (!ValidateRegistration()) return Forbid(); - var result = await swarmOperations.RemoteCommitRecieved(RequestRegistrationId, cancellationToken); + var result = await swarmOperations.RemoteCommitReceived(RequestRegistrationId, cancellationToken); if (!result) return Conflict(); return NoContent(); diff --git a/src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs b/src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs index a1c0a276cda..dd9c01b7830 100644 --- a/src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs +++ b/src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs @@ -56,6 +56,6 @@ public interface ISwarmOperations : ISwarmUpdateAborter /// The registration . /// The for the operation. /// A representing the running operation. - ValueTask RemoteCommitRecieved(Guid registrationId, CancellationToken cancellationToken); + ValueTask RemoteCommitReceived(Guid registrationId, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Swarm/SwarmService.cs b/src/Tgstation.Server.Host/Swarm/SwarmService.cs index 7340d4b25df..ba0a117b582 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmService.cs @@ -589,7 +589,7 @@ public async ValueTask RegisterNode(Api.Models.Internal.SwarmServer node, } /// - public async ValueTask RemoteCommitRecieved(Guid registrationId, CancellationToken cancellationToken) + public async ValueTask RemoteCommitReceived(Guid registrationId, CancellationToken cancellationToken) { var localUpdateOperation = updateOperation; if (!swarmController) diff --git a/tests/DMAPI/LongRunning/Test.dm b/tests/DMAPI/LongRunning/Test.dm index bed428eceb2..dad73d40e40 100644 --- a/tests/DMAPI/LongRunning/Test.dm +++ b/tests/DMAPI/LongRunning/Test.dm @@ -140,7 +140,7 @@ var/run_bridge_test kajigger_test = TRUE return "we love casting spells" - TgsChatBroadcast(new /datum/tgs_message_content("Recieved non-tgs topic: `[T]`")) + TgsChatBroadcast(new /datum/tgs_message_content("Received non-tgs topic: `[T]`")) return "feck" @@ -179,7 +179,7 @@ var/received_health_check = FALSE /datum/tgs_event_handler/impl/HandleEvent(event_code, ...) set waitfor = FALSE - world.TgsChatBroadcast(new /datum/tgs_message_content("Recieved event: `[json_encode(args)]`")) + world.TgsChatBroadcast(new /datum/tgs_message_content("Received event: `[json_encode(args)]`")) if(event_code == TGS_EVENT_HEALTH_CHECK) received_health_check = TRUE From 0ca70d809133e6f1a4106e5a633dc02bfc0bd223 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 05:18:16 -0400 Subject: [PATCH 137/717] Fix API things relating to ByondVersion and ByondRights --- .../Models/Internal/InstancePermissionSet.cs | 19 ++++++------------- .../Models/Response/CompileJobResponse.cs | 7 ++++--- .../InstancePermissionSetController.cs | 8 ++++++-- .../Models/CompileJob.cs | 5 ++++- .../Models/InstancePermissionSet.cs | 5 ++++- .../Security/AuthenticationContext.cs | 1 + 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs b/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs index 94ec3c5246e..0081d79e8f6 100644 --- a/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs +++ b/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs @@ -25,19 +25,6 @@ public abstract class InstancePermissionSet [Required] public InstancePermissionSetRights? InstancePermissionSetRights { get; set; } - /// - /// The of the . - /// - [NotMapped] - [JsonIgnore] - public EngineRights? EngineRights - { -#pragma warning disable CS0618 // Type or member is obsolete - get => ByondRights; - set => ByondRights = value; -#pragma warning restore CS0618 // Type or member is obsolete - } - /// /// The legacy of the . /// @@ -45,6 +32,12 @@ public EngineRights? EngineRights [Obsolete("Use EngineRights instead")] public EngineRights? ByondRights { get; set; } + /// + /// The of the . + /// + [NotMapped] + public EngineRights? EngineRights { get; set; } + /// /// The of the . /// diff --git a/src/Tgstation.Server.Api/Models/Response/CompileJobResponse.cs b/src/Tgstation.Server.Api/Models/Response/CompileJobResponse.cs index b38f11dcc0b..0ad0283749a 100644 --- a/src/Tgstation.Server.Api/Models/Response/CompileJobResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/CompileJobResponse.cs @@ -20,12 +20,13 @@ public sealed class CompileJobResponse : CompileJob /// /// The the was made with. /// - public EngineVersion? ByondVersion { get; set; } + [Obsolete("Use EngineVersion instead.")] + public string? ByondVersion { get; set; } /// - /// The the was made with. + /// The the was made with. /// - public EngineType? Engine { get; set; } + public EngineVersion? EngineVersion { get; set; } /// /// The origin of the repository the compile job was built from. diff --git a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs index 381cae1bc7d..14288712082 100644 --- a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs @@ -93,7 +93,9 @@ public async ValueTask Create([FromBody] InstancePermissionSetReq var dbUser = new InstancePermissionSet { - EngineRights = RightsHelper.Clamp(model.EngineRights ?? EngineRights.None), +#pragma warning disable CS0618 // Type or member is obsolete + EngineRights = RightsHelper.Clamp(model.EngineRights ?? model.ByondRights ?? EngineRights.None), +#pragma warning restore CS0618 // Type or member is obsolete ChatBotRights = RightsHelper.Clamp(model.ChatBotRights ?? ChatBotRights.None), ConfigurationRights = RightsHelper.Clamp(model.ConfigurationRights ?? ConfigurationRights.None), DreamDaemonRights = RightsHelper.Clamp(model.DreamDaemonRights ?? DreamDaemonRights.None), @@ -138,7 +140,9 @@ public async ValueTask Update([FromBody] InstancePermissionSetReq if (originalPermissionSet == null) return this.Gone(); - originalPermissionSet.EngineRights = RightsHelper.Clamp(model.EngineRights ?? originalPermissionSet.EngineRights.Value); +#pragma warning disable CS0618 // Type or member is obsolete + originalPermissionSet.ByondRights = RightsHelper.Clamp(model.EngineRights ?? model.ByondRights ?? originalPermissionSet.EngineRights.Value); +#pragma warning restore CS0618 // Type or member is obsolete originalPermissionSet.RepositoryRights = RightsHelper.Clamp(model.RepositoryRights ?? originalPermissionSet.RepositoryRights.Value); originalPermissionSet.InstancePermissionSetRights = RightsHelper.Clamp(model.InstancePermissionSetRights ?? originalPermissionSet.InstancePermissionSetRights.Value); originalPermissionSet.ChatBotRights = RightsHelper.Clamp(model.ChatBotRights ?? originalPermissionSet.ChatBotRights.Value); diff --git a/src/Tgstation.Server.Host/Models/CompileJob.cs b/src/Tgstation.Server.Host/Models/CompileJob.cs index 7f69e618ff8..4b43fd049c0 100644 --- a/src/Tgstation.Server.Host/Models/CompileJob.cs +++ b/src/Tgstation.Server.Host/Models/CompileJob.cs @@ -90,7 +90,10 @@ public override Version DMApiVersion Job = Job.ToApi(), Output = Output, RevisionInformation = RevisionInformation.ToApi(), - ByondVersion = Api.Models.Internal.EngineVersion.TryParse(ByondVersion, out var version) +#pragma warning disable CS0618 // Type or member is obsolete + ByondVersion = ByondVersion, +#pragma warning restore CS0618 // Type or member is obsolete + EngineVersion = Api.Models.Internal.EngineVersion.TryParse(ByondVersion, out var version) ? version : throw new InvalidOperationException($"Failed to parse BYOND version: {ByondVersion}"), MinimumSecurityLevel = MinimumSecurityLevel, diff --git a/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs b/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs index 623e920734b..c4436bd795c 100644 --- a/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs +++ b/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs @@ -32,7 +32,10 @@ public sealed class InstancePermissionSet : Api.Models.Internal.InstancePermissi /// public InstancePermissionSetResponse ToApi() => new InstancePermissionSetResponse { - EngineRights = EngineRights, +#pragma warning disable CS0618 // Type or member is obsolete + ByondRights = ByondRights, + EngineRights = ByondRights, +#pragma warning restore CS0618 // Type or member is obsolete ChatBotRights = ChatBotRights, ConfigurationRights = ConfigurationRights, DreamDaemonRights = DreamDaemonRights, diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContext.cs b/src/Tgstation.Server.Host/Security/AuthenticationContext.cs index 105c7f98371..1b19fc46d33 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContext.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContext.cs @@ -73,6 +73,7 @@ public ulong GetRight(RightsType rightsType) if (right == null) throw new InvalidOperationException("A user right was null!"); + return (ulong)right; } } From 7643e91f841e5ccd9d0f2b177ec5b2faf5d50878 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 05:23:28 -0400 Subject: [PATCH 138/717] Fix `EngineController.Update` permissions --- .../Controllers/EngineController.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/EngineController.cs b/src/Tgstation.Server.Host/Controllers/EngineController.cs index 83f69919917..47c9044f738 100644 --- a/src/Tgstation.Server.Host/Controllers/EngineController.cs +++ b/src/Tgstation.Server.Host/Controllers/EngineController.cs @@ -151,8 +151,15 @@ public async ValueTask Update([FromBody] EngineVersionRequest mod var uploadingZip = model.UploadCustomZip == true; var userByondRights = AuthenticationContext.InstancePermissionSet.EngineRights.Value; - if ((!userByondRights.HasFlag(EngineRights.InstallOfficialOrChangeActiveByondVersion) && !uploadingZip) - || (!userByondRights.HasFlag(EngineRights.InstallCustomByondVersion) && uploadingZip)) + var isByondEngine = model.EngineVersion.Engine.Value == EngineType.Byond; + var officialPerm = isByondEngine + ? EngineRights.InstallOfficialOrChangeActiveByondVersion + : EngineRights.InstallOfficialOrChangeActiveOpenDreamVersion; + var customPerm = isByondEngine + ? EngineRights.InstallCustomByondVersion + : EngineRights.InstallCustomOpenDreamVersion; + if ((!userByondRights.HasFlag(officialPerm) && !uploadingZip) + || (!userByondRights.HasFlag(customPerm) && uploadingZip)) return Forbid(); // remove cruff fields From 8eb8976629417ea33179098aa84cf8c89ed4632d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 05:31:15 -0400 Subject: [PATCH 139/717] Default to new EngineVersion property in model --- .../Models/Internal/InstancePermissionSet.cs | 5 +++-- .../Controllers/InstancePermissionSetController.cs | 2 +- .../Models/InstancePermissionSet.cs | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs b/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs index 0081d79e8f6..21d1f18d2f6 100644 --- a/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs +++ b/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs @@ -30,13 +30,14 @@ public abstract class InstancePermissionSet /// [Required] [Obsolete("Use EngineRights instead")] + [NotMapped] public EngineRights? ByondRights { get; set; } /// /// The of the . /// - [NotMapped] - public EngineRights? EngineRights { get; set; } + [Required] + public virtual EngineRights? EngineRights { get; set; } /// /// The of the . diff --git a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs index 14288712082..f25bcea52d3 100644 --- a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs @@ -141,7 +141,7 @@ public async ValueTask Update([FromBody] InstancePermissionSetReq return this.Gone(); #pragma warning disable CS0618 // Type or member is obsolete - originalPermissionSet.ByondRights = RightsHelper.Clamp(model.EngineRights ?? model.ByondRights ?? originalPermissionSet.EngineRights.Value); + originalPermissionSet.EngineRights = RightsHelper.Clamp(model.EngineRights ?? model.ByondRights ?? originalPermissionSet.EngineRights.Value); #pragma warning restore CS0618 // Type or member is obsolete originalPermissionSet.RepositoryRights = RightsHelper.Clamp(model.RepositoryRights ?? originalPermissionSet.RepositoryRights.Value); originalPermissionSet.InstancePermissionSetRights = RightsHelper.Clamp(model.InstancePermissionSetRights ?? originalPermissionSet.InstancePermissionSetRights.Value); diff --git a/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs b/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs index c4436bd795c..af21f7f8513 100644 --- a/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs +++ b/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs @@ -1,6 +1,8 @@ using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using Tgstation.Server.Api.Models.Response; +using Tgstation.Server.Api.Rights; namespace Tgstation.Server.Host.Models { @@ -29,13 +31,21 @@ public sealed class InstancePermissionSet : Api.Models.Internal.InstancePermissi [Required] public PermissionSet PermissionSet { get; set; } + /// + [Column("ByondRights")] + public override EngineRights? EngineRights + { + get => base.EngineRights; + set => base.EngineRights = value; + } + /// public InstancePermissionSetResponse ToApi() => new InstancePermissionSetResponse { #pragma warning disable CS0618 // Type or member is obsolete - ByondRights = ByondRights, - EngineRights = ByondRights, + ByondRights = EngineRights, #pragma warning restore CS0618 // Type or member is obsolete + EngineRights = EngineRights, ChatBotRights = ChatBotRights, ConfigurationRights = ConfigurationRights, DreamDaemonRights = DreamDaemonRights, From 22707da976c8e1c9c2a60cfa619cab4ccacd2bbb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 05:32:41 -0400 Subject: [PATCH 140/717] Additional logging --- .../Components/Engine/WindowsOpenDreamInstaller.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index 71c35eb7652..e9b3b9d6be3 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -71,6 +71,7 @@ public override ValueTask Install(EngineVersion version, string installPath, Can protected override async ValueTask HandleExtremelyLongPathOperation(Func shortenedPathOperation, string originalPath, CancellationToken cancellationToken) { var shortPath = $"C:/{Guid.NewGuid()}"; + Logger.LogDebug("Shortening path for build from {long} to {short}...", originalPath, shortPath); await symlinkFactory.CreateSymbolicLink(originalPath, shortPath, cancellationToken); try { From cf0194b54308e77271c38f977e295942e56ae8a9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 05:33:41 -0400 Subject: [PATCH 141/717] Fix engine version ordering in controller --- src/Tgstation.Server.Host/Controllers/EngineController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Controllers/EngineController.cs b/src/Tgstation.Server.Host/Controllers/EngineController.cs index 47c9044f738..7b9dbe3aea3 100644 --- a/src/Tgstation.Server.Host/Controllers/EngineController.cs +++ b/src/Tgstation.Server.Host/Controllers/EngineController.cs @@ -115,7 +115,7 @@ public ValueTask List([FromQuery] int? page, [FromQuery] int? pag EngineVersion = x, }) .AsQueryable() - .OrderBy(x => x.EngineVersion))), + .OrderBy(x => x.EngineVersion.ToString()))), null, page, pageSize, From 08e16c1cabf38f9b65bbb9001a86d75b7eef1f21 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 05:51:34 -0400 Subject: [PATCH 142/717] Fix path correction in OpenDreamInstaller --- .../Components/Engine/OpenDreamInstaller.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 6aa5e728fbe..a1bda4f50ba 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -186,7 +186,7 @@ public override async ValueTask Install(EngineVersion version, string installPat dirPath, IOManager.ConcatPath( sourcePath, - IOManager.GetFileName(sourcePath)), + IOManager.GetFileName(dirPath)), cancellationToken)); var filesMoveTask = filesTask .Result @@ -195,7 +195,7 @@ public override async ValueTask Install(EngineVersion version, string installPat filePath, IOManager.ConcatPath( sourcePath, - IOManager.GetFileName(sourcePath)), + IOManager.GetFileName(filePath)), cancellationToken)); await Task.WhenAll(dirsMoveTasks.Concat(filesMoveTask)); From 6124b4c7857b98595681d2ad76aae810f4314ef7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 05:52:02 -0400 Subject: [PATCH 143/717] Fix Engine delete job title --- src/Tgstation.Server.Host/Controllers/EngineController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Controllers/EngineController.cs b/src/Tgstation.Server.Host/Controllers/EngineController.cs index 7b9dbe3aea3..2dcf3b64978 100644 --- a/src/Tgstation.Server.Host/Controllers/EngineController.cs +++ b/src/Tgstation.Server.Host/Controllers/EngineController.cs @@ -311,7 +311,7 @@ public async ValueTask Delete([FromBody] EngineVersionDeleteReque // run the install through the job manager var job = new Models.Job { - Description = $"Delete installed engine version {model}", + Description = $"Delete installed engine version {model.EngineVersion}", StartedBy = AuthenticationContext.User, CancelRightsType = RightsType.Engine, CancelRight = (ulong)( From 2ec897fb32daaad92bf07df3b5cc185925b633fb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 05:55:18 -0400 Subject: [PATCH 144/717] Make compiler step name engine agnostic --- src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index cc142b8ce03..a2947b53a4c 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -631,7 +631,7 @@ await eventConsumer.HandleEvent( cancellationToken); // run compiler - progressReporter.StageName = "Running DreamMaker"; + progressReporter.StageName = "Running Compiler"; var compileSuceeded = await RunDreamMaker(engineLock, job, cancellationToken); // Session takes ownership of the lock and Disposes it so save this for later From 63f08431bf23ec74adcd28e8b7fb846afc2ade6d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 05:57:15 -0400 Subject: [PATCH 145/717] Remove redundant check --- src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index a2947b53a4c..d06ba9dc53a 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -814,9 +814,6 @@ async ValueTask VerifyApi( validationStatus = controller.ApiValidationStatus; - if (requireValidate && validationStatus == ApiValidationStatus.NeverValidated) - throw new JobException(ErrorCode.DeploymentNeverValidated); - logger.LogTrace("API validation status: {validationStatus}", validationStatus); job.DMApiVersion = controller.DMApiVersion; From ba5823c631012ba91ce0360ebc85a2ed28610f77 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 09:40:43 -0400 Subject: [PATCH 146/717] Set minimum required OD commit to https://github.com/OpenDreamProject/OpenDream/commit/fab769776dada6b9bcad546094d78c604049e0e9 --- src/Tgstation.Server.Api/Models/ErrorCode.cs | 6 ++ .../Components/Engine/OpenDreamInstaller.cs | 3 + .../Live/Instance/InstanceTest.cs | 94 ++++++++++--------- .../Live/TestLiveServer.cs | 29 +++++- 4 files changed, 86 insertions(+), 46 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/ErrorCode.cs b/src/Tgstation.Server.Api/Models/ErrorCode.cs index 00800b4aa7a..4dba0e189c4 100644 --- a/src/Tgstation.Server.Api/Models/ErrorCode.cs +++ b/src/Tgstation.Server.Api/Models/ErrorCode.cs @@ -634,5 +634,11 @@ public enum ErrorCode : uint /// [Description("OpenDream could not be compiled due to being unable to locate the dotnet executable!")] OpenDreamCantFindDotnet, + + /// + /// Could not install OpenDream due to it not meeting the minimum version requirements. + /// + [Description("The specified OpenDream version is too old!")] + OpenDreamTooOld, } } diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index a1bda4f50ba..e279f0d0ccd 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -152,6 +152,9 @@ await repo.CheckoutObject( progressSection2, cancellationToken); + if (!await repo.ShaIsParent("fab769776dada6b9bcad546094d78c604049e0e9", cancellationToken)) + throw new JobException(ErrorCode.OpenDreamTooOld); + return new RepositoryEngineInstallationData(IOManager, repo, InstallationSourceSubDirectory); } catch diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index c674a3a42d0..c3e5b322944 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -84,6 +84,55 @@ public async Task RunTests( .Run(cancellationToken); } + public static async ValueTask DownloadEngineVersion( + EngineVersion compatVersion, + IInstanceClient instanceClient, + IFileDownloader fileDownloader, + CancellationToken cancellationToken) + { + var odRepoDir = Path.GetFullPath(Path.Combine(instanceClient.Metadata.Path, "..", "OpenDreamRepo")); + var tmpIOManager = new ResolvingIOManager(new DefaultIOManager(), odRepoDir); + + var mockOptions = new Mock>(); + mockOptions.SetupGet(x => x.Value).Returns(new GeneralConfiguration()); + IEngineInstaller byondInstaller = + compatVersion.Engine == EngineType.OpenDream + ? new OpenDreamInstaller( + new DefaultIOManager(), + Mock.Of>(), + new PlatformIdentifier(), + Mock.Of(), + new RepositoryManager( + new LibGit2RepositoryFactory( + Mock.Of>()), + new LibGit2Commands(), + tmpIOManager, + new NoopEventConsumer(), + Mock.Of(), + Mock.Of(), + Mock.Of>(), + Mock.Of>(), + new GeneralConfiguration()), + mockOptions.Object) + : new PlatformIdentifier().IsWindows + ? new WindowsByondInstaller( + Mock.Of(), + Mock.Of(), + fileDownloader, + Options.Create(new GeneralConfiguration()), + Mock.Of>()) + : new PosixByondInstaller( + Mock.Of(), + Mock.Of(), + fileDownloader, + Mock.Of>()); + + using var windowsByondInstaller = byondInstaller as WindowsByondInstaller; + + // get the bytes for stable + return await byondInstaller.DownloadVersion(compatVersion, null, cancellationToken); + } + public async Task RunCompatTests( EngineVersion compatVersion, IInstanceClient instanceClient, @@ -147,49 +196,10 @@ public async Task RunCompatTests( var jrt = new JobsRequiredTest(instanceClient.Jobs); - - var odRepoDir = Path.GetFullPath(Path.Combine(instanceClient.Metadata.Path, "..", "OpenDreamRepo")); - var tmpIOManager = new ResolvingIOManager(new DefaultIOManager(), odRepoDir); - - var mockOptions = new Mock>(); - mockOptions.SetupGet(x => x.Value).Returns(new GeneralConfiguration()); - IEngineInstaller byondInstaller = - compatVersion.Engine == EngineType.OpenDream - ? new OpenDreamInstaller( - new DefaultIOManager(), - Mock.Of>(), - new PlatformIdentifier(), - Mock.Of(), - new RepositoryManager( - new LibGit2RepositoryFactory( - Mock.Of>()), - new LibGit2Commands(), - tmpIOManager, - new NoopEventConsumer(), - Mock.Of(), - Mock.Of(), - Mock.Of>(), - Mock.Of>(), - new GeneralConfiguration()), - mockOptions.Object) - : new PlatformIdentifier().IsWindows - ? new WindowsByondInstaller( - Mock.Of(), - Mock.Of(), - fileDownloader, - Options.Create(new GeneralConfiguration()), - Mock.Of>()) - : new PosixByondInstaller( - Mock.Of(), - Mock.Of(), - fileDownloader, - Mock.Of>()); - - using var windowsByondInstaller = byondInstaller as WindowsByondInstaller; - - // get the bytes for stable EngineInstallResponse installJob2; - await using (var stableBytesMs = await TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(compatVersion, null, cancellationToken), cancellationToken)) + await using (var stableBytesMs = await TestingUtils.ExtractMemoryStreamFromInstallationData( + await DownloadEngineVersion(compatVersion, instanceClient, fileDownloader, cancellationToken), + cancellationToken)) { installJob2 = await instanceClient.Engine.SetActiveVersion(new EngineVersionRequest { diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 6e5a48dc914..83b721cad67 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -40,6 +40,7 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Extensions; +using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.System; using Tgstation.Server.Tests.Live.Instance; @@ -1385,15 +1386,35 @@ async Task RunInstanceTests() if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization await byondApiCompatTests; - var odCompatTests = FailFast( - instanceTest + async Task ODCompatTests() + { + var edgeODVersionTask = EngineTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellationToken); + ; + + var ex = await Assert.ThrowsExceptionAsync( + () => InstanceTest.DownloadEngineVersion( + new EngineVersion + { + Engine = EngineType.OpenDream, + SourceSHA = "f1dc153caf9d84cd1d0056e52286cc0163e3f4d3", // 1b4 verified version + }, + instanceClient, + fileDownloader, + cancellationToken).AsTask()); + + Assert.AreEqual(ErrorCode.OpenDreamTooOld, ex.ErrorCode); + + await instanceTest .RunCompatTests( - await EngineTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellationToken), + await edgeODVersionTask, adminClient.Instances.CreateClient(odInstance), odDMPort, odDDPort, server.HighPriorityDreamDaemon, - cancellationToken)); + cancellationToken); + } + + var odCompatTests = FailFast(ODCompatTests()); if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization await odCompatTests; From aa0ca834d627bf4409769b62bef2a65821fc2ebf Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 09:41:10 -0400 Subject: [PATCH 147/717] Sort usings --- .../Live/Instance/JobsRequiredTest.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsRequiredTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsRequiredTest.cs index c561d7abde4..8de482a9171 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsRequiredTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsRequiredTest.cs @@ -1,10 +1,9 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Collections.Generic; -using System.Text; +using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client.Components; From cba6d1b83815de75723a31b0281730bd250c75da Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 09:41:46 -0400 Subject: [PATCH 148/717] Test we're populating the old `CompileJob.ByondVersion` for compatibility --- .../Live/Instance/WatchdogTest.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 16900200519..b1016474051 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -1053,15 +1053,26 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken Assert.AreEqual(initialStatus.ActiveCompileJob.Id, daemonStatus.ActiveCompileJob.Id); var newerCompileJob = daemonStatus.StagedCompileJob; - Assert.AreNotEqual(daemonStatus.ActiveCompileJob.ByondVersion, newerCompileJob.ByondVersion); - Assert.AreEqual(versionToInstall, newerCompileJob.ByondVersion); + Assert.AreNotEqual(daemonStatus.ActiveCompileJob.EngineVersion, newerCompileJob.EngineVersion); + if (testVersion.Engine.Value == EngineType.Byond) +#pragma warning disable CS0618 // Type or member is obsolete + Assert.AreEqual( + new Version( + daemonStatus.ActiveCompileJob.EngineVersion.Version.Major, + daemonStatus.ActiveCompileJob.EngineVersion.Version.Minor, + daemonStatus.ActiveCompileJob.EngineVersion.CustomIteration ?? 0) + .ToString(), + daemonStatus.ActiveCompileJob.ByondVersion.ToString()); +#pragma warning restore CS0618 // Type or member is obsolete + + Assert.AreEqual(versionToInstall, newerCompileJob.EngineVersion); Assert.AreEqual(true, daemonStatus.SoftRestart); await CheckDMApiFail(daemonStatus.ActiveCompileJob, cancellationToken); daemonStatus = await TellWorldToReboot(cancellationToken); - Assert.AreEqual(versionToInstall, daemonStatus.ActiveCompileJob.ByondVersion); + Assert.AreEqual(versionToInstall, daemonStatus.ActiveCompileJob.EngineVersion); Assert.IsNull(daemonStatus.StagedCompileJob); await instanceClient.DreamDaemon.Shutdown(cancellationToken); From e8e0f12b45e18f5a084ec20b4661fdd553500a6e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 10:06:56 -0400 Subject: [PATCH 149/717] Workaround for https://github.com/OpenDreamProject/OpenDream/issues/1519 --- .../Components/Engine/OpenDreamInstallation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index 2840db98eb2..19b0d81ecaf 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -70,7 +70,7 @@ public override string FormatServerArguments( var parametersString = EncodeParameters(parameters, launchParameters); var loggingEnabled = logFilePath != null; - var arguments = $"--cvar {(loggingEnabled ? $"log.path=\"{logFilePath}\"" : "log.enabled=false")} --cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" \"{dmbProvider.DmbName}\""; + var arguments = $"--cvar {(loggingEnabled ? $"log.path=\"{logFilePath}\"" : "log.enabled=false")} --cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" \"./{dmbProvider.DmbName}\""; return arguments; } From 8f73c33d5e83e30b9229675a106addabc61e47df Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 10:40:05 -0400 Subject: [PATCH 150/717] Use CVar `opendream.json_path` to prevent unknown argument warning --- .../Components/Engine/OpenDreamInstallation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index 19b0d81ecaf..89546436015 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -70,7 +70,7 @@ public override string FormatServerArguments( var parametersString = EncodeParameters(parameters, launchParameters); var loggingEnabled = logFilePath != null; - var arguments = $"--cvar {(loggingEnabled ? $"log.path=\"{logFilePath}\"" : "log.enabled=false")} --cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" \"./{dmbProvider.DmbName}\""; + var arguments = $"--cvar {(loggingEnabled ? $"log.path=\"{logFilePath}\"" : "log.enabled=false")} --cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" --cvar opendream.json_path=\"./{dmbProvider.DmbName}\""; return arguments; } From 186d5d68dc8d7bdfccc12c5d8707d252846f494a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 10:41:05 -0400 Subject: [PATCH 151/717] Engine agnostic job name --- src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index 6cc1f27cabb..ba6e1d2caf4 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -86,7 +86,7 @@ public ValueTask Create(CancellationToken cancellationToken) var job = new Job { - Description = "Launch DreamDaemon", + Description = "Launch Watchdog", CancelRight = (ulong)DreamDaemonRights.Shutdown, CancelRightsType = RightsType.DreamDaemon, Instance = Instance, From 73fa2ee225a7e0d7c4a4f8cb6bc1214e67f1daa7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 11:40:12 -0400 Subject: [PATCH 152/717] Switch Byond column names to Engine in database --- .../Models/Internal/InstancePermissionSet.cs | 12 +- .../Database/DatabaseContext.cs | 18 +- ...2_MSRenameByondColumnsToEngine.Designer.cs | 1074 ++++++++++++++++ ...1021153302_MSRenameByondColumnsToEngine.cs | 44 + ...9_MYRenameByondColumnsToEngine.Designer.cs | 1108 +++++++++++++++++ ...1021153309_MYRenameByondColumnsToEngine.cs | 44 + ...6_PGRenameByondColumnsToEngine.Designer.cs | 1068 ++++++++++++++++ ...1021153316_PGRenameByondColumnsToEngine.cs | 242 ++++ ...3_SLRenameByondColumnsToEngine.Designer.cs | 1040 ++++++++++++++++ ...1021153323_SLRenameByondColumnsToEngine.cs | 44 + .../MySqlDatabaseContextModelSnapshot.cs | 8 +- ...PostgresSqlDatabaseContextModelSnapshot.cs | 8 +- .../SqlServerDatabaseContextModelSnapshot.cs | 8 +- .../SqliteDatabaseContextModelSnapshot.cs | 8 +- .../Models/CompileJob.cs | 2 + .../Models/InstancePermissionSet.cs | 10 - 16 files changed, 4706 insertions(+), 32 deletions(-) create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231021153302_MSRenameByondColumnsToEngine.Designer.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231021153302_MSRenameByondColumnsToEngine.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231021153309_MYRenameByondColumnsToEngine.Designer.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231021153309_MYRenameByondColumnsToEngine.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231021153316_PGRenameByondColumnsToEngine.Designer.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231021153316_PGRenameByondColumnsToEngine.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231021153323_SLRenameByondColumnsToEngine.Designer.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231021153323_SLRenameByondColumnsToEngine.cs diff --git a/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs b/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs index 21d1f18d2f6..863e034d096 100644 --- a/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs +++ b/src/Tgstation.Server.Api/Models/Internal/InstancePermissionSet.cs @@ -26,18 +26,18 @@ public abstract class InstancePermissionSet public InstancePermissionSetRights? InstancePermissionSetRights { get; set; } /// - /// The legacy of the . + /// The of the . /// [Required] - [Obsolete("Use EngineRights instead")] - [NotMapped] - public EngineRights? ByondRights { get; set; } + public EngineRights? EngineRights { get; set; } /// - /// The of the . + /// The legacy of the . /// [Required] - public virtual EngineRights? EngineRights { get; set; } + [Obsolete("Use EngineRights instead")] + [NotMapped] + public EngineRights? ByondRights { get; set; } /// /// The of the . diff --git a/src/Tgstation.Server.Host/Database/DatabaseContext.cs b/src/Tgstation.Server.Host/Database/DatabaseContext.cs index fbd7d0a38c1..938f34af7ec 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseContext.cs @@ -378,22 +378,22 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) /// /// Used by unit tests to remind us to setup the correct MSSQL migration downgrades. /// - internal static readonly Type MSLatestMigration = typeof(MSAddMapThreads); + internal static readonly Type MSLatestMigration = typeof(MSRenameByondColumnsToEngine); /// /// Used by unit tests to remind us to setup the correct MYSQL migration downgrades. /// - internal static readonly Type MYLatestMigration = typeof(MYAddMapThreads); + internal static readonly Type MYLatestMigration = typeof(MYRenameByondColumnsToEngine); /// /// Used by unit tests to remind us to setup the correct PostgresSQL migration downgrades. /// - internal static readonly Type PGLatestMigration = typeof(PGAddMapThreads); + internal static readonly Type PGLatestMigration = typeof(PGRenameByondColumnsToEngine); /// /// Used by unit tests to remind us to setup the correct SQLite migration downgrades. /// - internal static readonly Type SLLatestMigration = typeof(SLAddMapThreads); + internal static readonly Type SLLatestMigration = typeof(SLRenameByondColumnsToEngine); /// #pragma warning disable CA1502 // Cyclomatic complexity @@ -422,6 +422,16 @@ public async ValueTask SchemaDowngradeForServerVersion( string BadDatabaseType() => throw new ArgumentException($"Invalid DatabaseType: {currentDatabaseType}", nameof(currentDatabaseType)); + if (targetVersion < new Version(6, 0, 0)) + targetMigration = currentDatabaseType switch + { + DatabaseType.MySql => nameof(MYAddMapThreads), + DatabaseType.PostgresSql => nameof(PGAddMapThreads), + DatabaseType.SqlServer => nameof(MSAddMapThreads), + DatabaseType.Sqlite => nameof(SLAddMapThreads), + _ => BadDatabaseType(), + }; + if (targetVersion < new Version(5, 13, 0)) targetMigration = currentDatabaseType switch { diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231021153302_MSRenameByondColumnsToEngine.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231021153302_MSRenameByondColumnsToEngine.Designer.cs new file mode 100644 index 00000000000..0bbedf9ac17 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231021153302_MSRenameByondColumnsToEngine.Designer.cs @@ -0,0 +1,1074 @@ +// +using System; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(SqlServerDatabaseContext))] + [Migration("20231021153302_MSRenameByondColumnsToEngine")] + partial class MSRenameByondColumnsToEngine + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChannelLimit") + .HasColumnType("int"); + + b.Property("ConnectionString") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChatSettingsId") + .HasColumnType("bigint"); + + b.Property("DiscordChannelId") + .HasColumnType("decimal(20,0)"); + + b.Property("IrcChannel") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("IsSystemChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("Tag") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + 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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ByondVersion") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("EngineVersion"); + + 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("GitHubDeploymentId") + .HasColumnType("int"); + + b.Property("GitHubRepoId") + .HasColumnType("bigint"); + + b.Property("JobId") + .HasColumnType("bigint"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("int"); + + b.Property("Output") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RepositoryOrigin") + .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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AdditionalParameters") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("bit"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("bit"); + + b.Property("DumpOnHealthCheckRestart") + .IsRequired() + .HasColumnType("bit"); + + b.Property("HealthCheckSeconds") + .HasColumnType("bigint"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("LogOutput") + .IsRequired() + .HasColumnType("bit"); + + b.Property("MapThreads") + .HasColumnType("bigint"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("SecurityLevel") + .HasColumnType("int"); + + b.Property("StartProfiler") + .IsRequired() + .HasColumnType("bit"); + + b.Property("StartupTimeout") + .HasColumnType("bigint"); + + b.Property("TopicRequestTimeout") + .HasColumnType("bigint"); + + b.Property("Visibility") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApiValidationPort") + .HasColumnType("int"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("int"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("ProjectName") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("bit"); + + b.Property("Timeout") + .IsRequired() + .HasColumnType("time"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AutoUpdateInterval") + .HasColumnType("bigint"); + + b.Property("ChatBotLimit") + .HasColumnType("int"); + + b.Property("ConfigurationType") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Online") + .IsRequired() + .HasColumnType("bit"); + + b.Property("Path") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SwarmIdentifer") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique() + .HasFilter("[SwarmIdentifer] IS NOT NULL"); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ByondRights") + .HasColumnType("decimal(20,0)") + .HasColumnName("EngineRights"); + + 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("InstancePermissionSetRights") + .HasColumnType("decimal(20,0)"); + + b.Property("PermissionSetId") + .HasColumnType("bigint"); + + b.Property("RepositoryRights") + .HasColumnType("decimal(20,0)"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.HasIndex("PermissionSetId", "InstanceId") + .IsUnique(); + + b.ToTable("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + 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.OAuthConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ExternalUserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Provider") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("Provider", "ExternalUserId") + .IsUnique(); + + b.ToTable("OAuthConnections"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AdministrationRights") + .HasColumnType("decimal(20,0)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("InstanceManagerRights") + .HasColumnType("decimal(20,0)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique() + .HasFilter("[GroupId] IS NOT NULL"); + + b.HasIndex("UserId") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompileJobId") + .HasColumnType("bigint"); + + b.Property("InitialCompileJobId") + .HasColumnType("bigint"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("int"); + + b.Property("LaunchVisibility") + .HasColumnType("int"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("ProcessId") + .HasColumnType("int"); + + b.Property("RebootState") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.HasIndex("InitialCompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccessToken") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("AccessUser") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("bit"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("bit"); + + b.Property("CommitterEmail") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("CommitterName") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("bit"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("bit"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("bit"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("bit"); + + b.Property("UpdateSubmodules") + .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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + 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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("Timestamp") + .HasColumnType("datetimeoffset"); + + 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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Author") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Comment") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("MergedAt") + .HasColumnType("datetimeoffset"); + + b.Property("MergedById") + .HasColumnType("bigint"); + + b.Property("Number") + .HasColumnType("int"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("bigint"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanonicalName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("datetimeoffset"); + + b.Property("CreatedById") + .HasColumnType("bigint"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("bit"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastPasswordUpdate") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("SystemIdentifier") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique() + .HasFilter("[SystemIdentifier] IS NOT NULL"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("ChatSettings") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChatSettings"); + }); + + 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(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("InstancePermissionSets") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet") + .WithMany("InstancePermissionSets") + .HasForeignKey("PermissionSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); + }); + + 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(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "InitialCompileJob") + .WithMany() + .HasForeignKey("InitialCompileJobId"); + + b.Navigation("CompileJob"); + + b.Navigation("InitialCompileJob"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy") + .WithMany("CreatedUsers") + .HasForeignKey("CreatedById"); + + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithMany("Users") + .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231021153302_MSRenameByondColumnsToEngine.cs b/src/Tgstation.Server.Host/Database/Migrations/20231021153302_MSRenameByondColumnsToEngine.cs new file mode 100644 index 00000000000..b142ab007b5 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231021153302_MSRenameByondColumnsToEngine.cs @@ -0,0 +1,44 @@ +using System; + +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + public partial class MSRenameByondColumnsToEngine : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.RenameColumn( + name: "ByondRights", + table: "InstancePermissionSets", + newName: "EngineRights"); + + migrationBuilder.RenameColumn( + name: "ByondVersion", + table: "CompileJobs", + newName: "EngineVersion"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.RenameColumn( + name: "EngineRights", + table: "InstancePermissionSets", + newName: "ByondRights"); + + migrationBuilder.RenameColumn( + name: "EngineVersion", + table: "CompileJobs", + newName: "ByondVersion"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231021153309_MYRenameByondColumnsToEngine.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231021153309_MYRenameByondColumnsToEngine.Designer.cs new file mode 100644 index 00000000000..74af14ef759 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231021153309_MYRenameByondColumnsToEngine.Designer.cs @@ -0,0 +1,1108 @@ +// +using System; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(MySqlDatabaseContext))] + [Migration("20231021153309_MYRenameByondColumnsToEngine")] + partial class MYRenameByondColumnsToEngine + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6") + .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() + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ConnectionString"), "utf8mb4"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(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") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("IrcChannel"), "utf8mb4"); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("IsSystemChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("Tag") + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Tag"), "utf8mb4"); + + 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") + .HasColumnName("EngineVersion"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ByondVersion"), "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"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("DmeName"), "utf8mb4"); + + b.Property("GitHubDeploymentId") + .HasColumnType("int"); + + b.Property("GitHubRepoId") + .HasColumnType("bigint"); + + b.Property("JobId") + .HasColumnType("bigint"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("int"); + + b.Property("Output") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Output"), "utf8mb4"); + + b.Property("RepositoryOrigin") + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("RepositoryOrigin"), "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("AdditionalParameters") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("AdditionalParameters"), "utf8mb4"); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("DumpOnHealthCheckRestart") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("HealthCheckSeconds") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("LogOutput") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("MapThreads") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("Port") + .IsRequired() + .HasColumnType("smallint unsigned"); + + b.Property("SecurityLevel") + .HasColumnType("int"); + + b.Property("StartProfiler") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("StartupTimeout") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("TopicRequestTimeout") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("Visibility") + .HasColumnType("int"); + + 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") + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ProjectName"), "utf8mb4"); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("Timeout") + .IsRequired() + .HasColumnType("time(6)"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + 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() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Name"), "utf8mb4"); + + b.Property("Online") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("Path") + .IsRequired() + .HasColumnType("varchar(255)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Path"), "utf8mb4"); + + b.Property("SwarmIdentifer") + .HasColumnType("varchar(255)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("SwarmIdentifer"), "utf8mb4"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique(); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ByondRights") + .HasColumnType("bigint unsigned") + .HasColumnName("EngineRights"); + + 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("InstancePermissionSetRights") + .HasColumnType("bigint unsigned"); + + b.Property("PermissionSetId") + .HasColumnType("bigint"); + + b.Property("RepositoryRights") + .HasColumnType("bigint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.HasIndex("PermissionSetId", "InstanceId") + .IsUnique(); + + b.ToTable("InstancePermissionSets"); + }); + + 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"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Description"), "utf8mb4"); + + b.Property("ErrorCode") + .HasColumnType("int unsigned"); + + b.Property("ExceptionDetails") + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ExceptionDetails"), "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.OAuthConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ExternalUserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ExternalUserId"), "utf8mb4"); + + b.Property("Provider") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("Provider", "ExternalUserId") + .IsUnique(); + + b.ToTable("OAuthConnections"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AdministrationRights") + .HasColumnType("bigint unsigned"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("InstanceManagerRights") + .HasColumnType("bigint unsigned"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique(); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("AccessIdentifier"), "utf8mb4"); + + b.Property("CompileJobId") + .HasColumnType("bigint"); + + b.Property("InitialCompileJobId") + .HasColumnType("bigint"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("int"); + + b.Property("LaunchVisibility") + .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.HasIndex("InitialCompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccessToken") + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("AccessToken"), "utf8mb4"); + + b.Property("AccessUser") + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("AccessUser"), "utf8mb4"); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("CommitterEmail") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("CommitterEmail"), "utf8mb4"); + + b.Property("CommitterName") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("CommitterName"), "utf8mb4"); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("tinyint(1)"); + + 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.Property("UpdateSubmodules") + .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() + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("CommitSha"), "utf8mb4"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("OriginCommitSha"), "utf8mb4"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + 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("Author") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Author"), "utf8mb4"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("BodyAtMerge"), "utf8mb4"); + + b.Property("Comment") + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Comment"), "utf8mb4"); + + b.Property("MergedAt") + .HasColumnType("datetime(6)"); + + b.Property("MergedById") + .HasColumnType("bigint"); + + b.Property("Number") + .HasColumnType("int"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("bigint"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("TargetCommitSha"), "utf8mb4"); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("TitleAtMerge"), "utf8mb4"); + + b.Property("Url") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Url"), "utf8mb4"); + + 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"); + + b.Property("CanonicalName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("CanonicalName"), "utf8mb4"); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("bigint"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastPasswordUpdate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Name"), "utf8mb4"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("PasswordHash"), "utf8mb4"); + + b.Property("SystemIdentifier") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("SystemIdentifier"), "utf8mb4"); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Name"), "utf8mb4"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("ChatSettings") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChatSettings"); + }); + + 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.Cascade) + .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("InstancePermissionSets") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet") + .WithMany("InstancePermissionSets") + .HasForeignKey("PermissionSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); + }); + + 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(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "InitialCompileJob") + .WithMany() + .HasForeignKey("InitialCompileJobId"); + + b.Navigation("CompileJob"); + + b.Navigation("InitialCompileJob"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy") + .WithMany("CreatedUsers") + .HasForeignKey("CreatedById"); + + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithMany("Users") + .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231021153309_MYRenameByondColumnsToEngine.cs b/src/Tgstation.Server.Host/Database/Migrations/20231021153309_MYRenameByondColumnsToEngine.cs new file mode 100644 index 00000000000..844b027d164 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231021153309_MYRenameByondColumnsToEngine.cs @@ -0,0 +1,44 @@ +using System; + +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + public partial class MYRenameByondColumnsToEngine : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.RenameColumn( + name: "ByondRights", + table: "InstancePermissionSets", + newName: "EngineRights"); + + migrationBuilder.RenameColumn( + name: "ByondVersion", + table: "CompileJobs", + newName: "EngineVersion"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.RenameColumn( + name: "EngineRights", + table: "InstancePermissionSets", + newName: "ByondRights"); + + migrationBuilder.RenameColumn( + name: "EngineVersion", + table: "CompileJobs", + newName: "ByondVersion"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231021153316_PGRenameByondColumnsToEngine.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231021153316_PGRenameByondColumnsToEngine.Designer.cs new file mode 100644 index 00000000000..c1e33d9358b --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231021153316_PGRenameByondColumnsToEngine.Designer.cs @@ -0,0 +1,1068 @@ +// +using System; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(PostgresSqlDatabaseContext))] + [Migration("20231021153316_PGRenameByondColumnsToEngine")] + partial class PGRenameByondColumnsToEngine + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelLimit") + .HasColumnType("integer"); + + b.Property("ConnectionString") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Provider") + .HasColumnType("integer"); + + 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"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChatSettingsId") + .HasColumnType("bigint"); + + b.Property("DiscordChannelId") + .HasColumnType("numeric(20,0)"); + + b.Property("IrcChannel") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("IsSystemChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("Tag") + .HasMaxLength(10000) + .HasColumnType("character varying(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"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ByondVersion") + .IsRequired() + .HasColumnType("text") + .HasColumnName("EngineVersion"); + + b.Property("DMApiMajorVersion") + .HasColumnType("integer"); + + b.Property("DMApiMinorVersion") + .HasColumnType("integer"); + + b.Property("DMApiPatchVersion") + .HasColumnType("integer"); + + b.Property("DirectoryName") + .IsRequired() + .HasColumnType("uuid"); + + b.Property("DmeName") + .IsRequired() + .HasColumnType("text"); + + b.Property("GitHubDeploymentId") + .HasColumnType("integer"); + + b.Property("GitHubRepoId") + .HasColumnType("bigint"); + + b.Property("JobId") + .HasColumnType("bigint"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("integer"); + + b.Property("Output") + .IsRequired() + .HasColumnType("text"); + + b.Property("RepositoryOrigin") + .HasColumnType("text"); + + 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"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AdditionalParameters") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("DumpOnHealthCheckRestart") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("HealthCheckSeconds") + .HasColumnType("bigint"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("LogOutput") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("MapThreads") + .HasColumnType("bigint"); + + b.Property("Port") + .HasColumnType("integer"); + + b.Property("SecurityLevel") + .HasColumnType("integer"); + + b.Property("StartProfiler") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("StartupTimeout") + .HasColumnType("bigint"); + + b.Property("TopicRequestTimeout") + .HasColumnType("bigint"); + + b.Property("Visibility") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApiValidationPort") + .HasColumnType("integer"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("integer"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("ProjectName") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("Timeout") + .IsRequired() + .HasColumnType("interval"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AutoUpdateInterval") + .HasColumnType("bigint"); + + b.Property("ChatBotLimit") + .HasColumnType("integer"); + + b.Property("ConfigurationType") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Online") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("SwarmIdentifer") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique(); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ByondRights") + .HasColumnType("numeric(20,0)") + .HasColumnName("EngineRights"); + + b.Property("ChatBotRights") + .HasColumnType("numeric(20,0)"); + + b.Property("ConfigurationRights") + .HasColumnType("numeric(20,0)"); + + b.Property("DreamDaemonRights") + .HasColumnType("numeric(20,0)"); + + b.Property("DreamMakerRights") + .HasColumnType("numeric(20,0)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("numeric(20,0)"); + + b.Property("PermissionSetId") + .HasColumnType("bigint"); + + b.Property("RepositoryRights") + .HasColumnType("numeric(20,0)"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.HasIndex("PermissionSetId", "InstanceId") + .IsUnique(); + + b.ToTable("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CancelRight") + .HasColumnType("numeric(20,0)"); + + b.Property("CancelRightsType") + .HasColumnType("numeric(20,0)"); + + b.Property("Cancelled") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("CancelledById") + .HasColumnType("bigint"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ErrorCode") + .HasColumnType("bigint"); + + b.Property("ExceptionDetails") + .HasColumnType("text"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("StartedAt") + .IsRequired() + .HasColumnType("timestamp with time zone"); + + b.Property("StartedById") + .HasColumnType("bigint"); + + b.Property("StoppedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CancelledById"); + + b.HasIndex("InstanceId"); + + b.HasIndex("StartedById"); + + b.ToTable("Jobs"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ExternalUserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Provider") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("Provider", "ExternalUserId") + .IsUnique(); + + b.ToTable("OAuthConnections"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AdministrationRights") + .HasColumnType("numeric(20,0)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("InstanceManagerRights") + .HasColumnType("numeric(20,0)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique(); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("text"); + + b.Property("CompileJobId") + .HasColumnType("bigint"); + + b.Property("InitialCompileJobId") + .HasColumnType("bigint"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("integer"); + + b.Property("LaunchVisibility") + .HasColumnType("integer"); + + b.Property("Port") + .HasColumnType("integer"); + + b.Property("ProcessId") + .HasColumnType("integer"); + + b.Property("RebootState") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.HasIndex("InitialCompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessToken") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("AccessUser") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("CommitterEmail") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("CommitterName") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("UpdateSubmodules") + .IsRequired() + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("RepositorySettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + 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"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + 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"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Author") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Comment") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("MergedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MergedById") + .HasColumnType("bigint"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("bigint"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text"); + + 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"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CanonicalName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedById") + .HasColumnType("bigint"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastPasswordUpdate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SystemIdentifier") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("ChatSettings") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChatSettings"); + }); + + 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.Cascade) + .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("InstancePermissionSets") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet") + .WithMany("InstancePermissionSets") + .HasForeignKey("PermissionSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); + }); + + 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(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "InitialCompileJob") + .WithMany() + .HasForeignKey("InitialCompileJobId"); + + b.Navigation("CompileJob"); + + b.Navigation("InitialCompileJob"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy") + .WithMany("CreatedUsers") + .HasForeignKey("CreatedById"); + + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithMany("Users") + .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231021153316_PGRenameByondColumnsToEngine.cs b/src/Tgstation.Server.Host/Database/Migrations/20231021153316_PGRenameByondColumnsToEngine.cs new file mode 100644 index 00000000000..32a4a0957e6 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231021153316_PGRenameByondColumnsToEngine.cs @@ -0,0 +1,242 @@ +using System; + +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + public partial class PGRenameByondColumnsToEngine : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.RenameColumn( + name: "ByondRights", + table: "InstancePermissionSets", + newName: "EngineRights"); + + migrationBuilder.RenameColumn( + name: "ByondVersion", + table: "CompileJobs", + newName: "EngineVersion"); + + migrationBuilder.AlterColumn( + name: "InstanceManagerRights", + table: "PermissionSets", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20)"); + + migrationBuilder.AlterColumn( + name: "AdministrationRights", + table: "PermissionSets", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20)"); + + migrationBuilder.AlterColumn( + name: "CancelRightsType", + table: "Jobs", + type: "numeric(20,0)", + nullable: true, + oldClrType: typeof(decimal), + oldType: "numeric(20)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "CancelRight", + table: "Jobs", + type: "numeric(20,0)", + nullable: true, + oldClrType: typeof(decimal), + oldType: "numeric(20)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "RepositoryRights", + table: "InstancePermissionSets", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20)"); + + migrationBuilder.AlterColumn( + name: "InstancePermissionSetRights", + table: "InstancePermissionSets", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20)"); + + migrationBuilder.AlterColumn( + name: "DreamMakerRights", + table: "InstancePermissionSets", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20)"); + + migrationBuilder.AlterColumn( + name: "DreamDaemonRights", + table: "InstancePermissionSets", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20)"); + + migrationBuilder.AlterColumn( + name: "ConfigurationRights", + table: "InstancePermissionSets", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20)"); + + migrationBuilder.AlterColumn( + name: "ChatBotRights", + table: "InstancePermissionSets", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20)"); + + migrationBuilder.AlterColumn( + name: "EngineRights", + table: "InstancePermissionSets", + type: "numeric(20,0)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20)"); + + migrationBuilder.AlterColumn( + name: "DiscordChannelId", + table: "ChatChannels", + type: "numeric(20,0)", + nullable: true, + oldClrType: typeof(decimal), + oldType: "numeric(20)", + oldNullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.RenameColumn( + name: "EngineRights", + table: "InstancePermissionSets", + newName: "ByondRights"); + + migrationBuilder.RenameColumn( + name: "EngineVersion", + table: "CompileJobs", + newName: "ByondVersion"); + + migrationBuilder.AlterColumn( + name: "InstanceManagerRights", + table: "PermissionSets", + type: "numeric(20)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "AdministrationRights", + table: "PermissionSets", + type: "numeric(20)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "CancelRightsType", + table: "Jobs", + type: "numeric(20)", + nullable: true, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "CancelRight", + table: "Jobs", + type: "numeric(20)", + nullable: true, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "RepositoryRights", + table: "InstancePermissionSets", + type: "numeric(20)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "InstancePermissionSetRights", + table: "InstancePermissionSets", + type: "numeric(20)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "DreamMakerRights", + table: "InstancePermissionSets", + type: "numeric(20)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "DreamDaemonRights", + table: "InstancePermissionSets", + type: "numeric(20)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "ConfigurationRights", + table: "InstancePermissionSets", + type: "numeric(20)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "ChatBotRights", + table: "InstancePermissionSets", + type: "numeric(20)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "ByondRights", + table: "InstancePermissionSets", + type: "numeric(20)", + nullable: false, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)"); + + migrationBuilder.AlterColumn( + name: "DiscordChannelId", + table: "ChatChannels", + type: "numeric(20)", + nullable: true, + oldClrType: typeof(decimal), + oldType: "numeric(20,0)", + oldNullable: true); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231021153323_SLRenameByondColumnsToEngine.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231021153323_SLRenameByondColumnsToEngine.Designer.cs new file mode 100644 index 00000000000..594d0bbc9d6 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231021153323_SLRenameByondColumnsToEngine.Designer.cs @@ -0,0 +1,1040 @@ +// +using System; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(SqliteDatabaseContext))] + [Migration("20231021153323_SLRenameByondColumnsToEngine")] + partial class SLRenameByondColumnsToEngine + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6"); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelLimit") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ConnectionString") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.Property("ReconnectionInterval") + .IsRequired() + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "Name") + .IsUnique(); + + b.ToTable("ChatBots"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChatSettingsId") + .HasColumnType("INTEGER"); + + b.Property("DiscordChannelId") + .HasColumnType("INTEGER"); + + b.Property("IrcChannel") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("IsSystemChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Tag") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + 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("INTEGER"); + + b.Property("ByondVersion") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("EngineVersion"); + + b.Property("DMApiMajorVersion") + .HasColumnType("INTEGER"); + + b.Property("DMApiMinorVersion") + .HasColumnType("INTEGER"); + + b.Property("DMApiPatchVersion") + .HasColumnType("INTEGER"); + + b.Property("DirectoryName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DmeName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("GitHubDeploymentId") + .HasColumnType("INTEGER"); + + b.Property("GitHubRepoId") + .HasColumnType("INTEGER"); + + b.Property("JobId") + .HasColumnType("INTEGER"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("Output") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RepositoryOrigin") + .HasColumnType("TEXT"); + + b.Property("RevisionInformationId") + .HasColumnType("INTEGER"); + + 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("INTEGER"); + + b.Property("AdditionalParameters") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("DumpOnHealthCheckRestart") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("HealthCheckSeconds") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("LogOutput") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("MapThreads") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Port") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("SecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("StartProfiler") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("StartupTimeout") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("TopicRequestTimeout") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Visibility") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ApiValidationPort") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("ProjectName") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Timeout") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoUpdateInterval") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ChatBotLimit") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ConfigurationType") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Online") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SwarmIdentifer") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique(); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ByondRights") + .HasColumnType("INTEGER") + .HasColumnName("EngineRights"); + + b.Property("ChatBotRights") + .HasColumnType("INTEGER"); + + b.Property("ConfigurationRights") + .HasColumnType("INTEGER"); + + b.Property("DreamDaemonRights") + .HasColumnType("INTEGER"); + + b.Property("DreamMakerRights") + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("INTEGER"); + + b.Property("PermissionSetId") + .HasColumnType("INTEGER"); + + b.Property("RepositoryRights") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.HasIndex("PermissionSetId", "InstanceId") + .IsUnique(); + + b.ToTable("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CancelRight") + .HasColumnType("INTEGER"); + + b.Property("CancelRightsType") + .HasColumnType("INTEGER"); + + b.Property("Cancelled") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("CancelledById") + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ErrorCode") + .HasColumnType("INTEGER"); + + b.Property("ExceptionDetails") + .HasColumnType("TEXT"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("StartedAt") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartedById") + .HasColumnType("INTEGER"); + + b.Property("StoppedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CancelledById"); + + b.HasIndex("InstanceId"); + + b.HasIndex("StartedById"); + + b.ToTable("Jobs"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalUserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("Provider", "ExternalUserId") + .IsUnique(); + + b.ToTable("OAuthConnections"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AdministrationRights") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.Property("InstanceManagerRights") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique(); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CompileJobId") + .HasColumnType("INTEGER"); + + b.Property("InitialCompileJobId") + .HasColumnType("INTEGER"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("LaunchVisibility") + .HasColumnType("INTEGER"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("ProcessId") + .HasColumnType("INTEGER"); + + b.Property("RebootState") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.HasIndex("InitialCompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("AccessUser") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("CommitterEmail") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("CommitterName") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("UpdateSubmodules") + .IsRequired() + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("RepositorySettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RevisionInformationId") + .HasColumnType("INTEGER"); + + b.Property("TestMergeId") + .HasColumnType("INTEGER"); + + 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("INTEGER"); + + b.Property("CommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "CommitSha") + .IsUnique(); + + b.ToTable("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Author") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("MergedAt") + .HasColumnType("TEXT"); + + b.Property("MergedById") + .HasColumnType("INTEGER"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + 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("INTEGER"); + + b.Property("CanonicalName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.Property("LastPasswordUpdate") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("SystemIdentifier") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("ChatSettings") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChatSettings"); + }); + + 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(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("InstancePermissionSets") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet") + .WithMany("InstancePermissionSets") + .HasForeignKey("PermissionSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); + }); + + 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(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "InitialCompileJob") + .WithMany() + .HasForeignKey("InitialCompileJobId"); + + b.Navigation("CompileJob"); + + b.Navigation("InitialCompileJob"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy") + .WithMany("CreatedUsers") + .HasForeignKey("CreatedById"); + + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithMany("Users") + .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231021153323_SLRenameByondColumnsToEngine.cs b/src/Tgstation.Server.Host/Database/Migrations/20231021153323_SLRenameByondColumnsToEngine.cs new file mode 100644 index 00000000000..755fc8d06ee --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231021153323_SLRenameByondColumnsToEngine.cs @@ -0,0 +1,44 @@ +using System; + +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + public partial class SLRenameByondColumnsToEngine : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.RenameColumn( + name: "ByondRights", + table: "InstancePermissionSets", + newName: "EngineRights"); + + migrationBuilder.RenameColumn( + name: "ByondVersion", + table: "CompileJobs", + newName: "EngineVersion"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.RenameColumn( + name: "EngineRights", + table: "InstancePermissionSets", + newName: "ByondRights"); + + migrationBuilder.RenameColumn( + name: "EngineVersion", + table: "CompileJobs", + newName: "ByondVersion"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs index f70cac88acf..0fe6ad0c6bc 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs @@ -16,7 +16,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "7.0.7") + .HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => @@ -121,7 +121,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ByondVersion") .IsRequired() - .HasColumnType("longtext"); + .HasColumnType("longtext") + .HasColumnName("EngineVersion"); MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ByondVersion"), "utf8mb4"); @@ -344,7 +345,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("bigint"); b.Property("ByondRights") - .HasColumnType("bigint unsigned"); + .HasColumnType("bigint unsigned") + .HasColumnName("EngineRights"); b.Property("ChatBotRights") .HasColumnType("bigint unsigned"); diff --git a/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs index aa74a6f86d5..bb9d55bc90d 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs @@ -16,7 +16,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "7.0.7") + .HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -121,7 +121,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ByondVersion") .IsRequired() - .HasColumnType("text"); + .HasColumnType("text") + .HasColumnName("EngineVersion"); b.Property("DMApiMajorVersion") .HasColumnType("integer"); @@ -326,7 +327,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("ByondRights") - .HasColumnType("numeric(20,0)"); + .HasColumnType("numeric(20,0)") + .HasColumnName("EngineRights"); b.Property("ChatBotRights") .HasColumnType("numeric(20,0)"); diff --git a/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs index 4534c99cf69..f0ce1f094d1 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs @@ -16,7 +16,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "7.0.7") + .HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -123,7 +123,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ByondVersion") .IsRequired() - .HasColumnType("nvarchar(max)"); + .HasColumnType("nvarchar(max)") + .HasColumnName("EngineVersion"); b.Property("DMApiMajorVersion") .HasColumnType("int"); @@ -329,7 +330,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("ByondRights") - .HasColumnType("decimal(20,0)"); + .HasColumnType("decimal(20,0)") + .HasColumnName("EngineRights"); b.Property("ChatBotRights") .HasColumnType("decimal(20,0)"); diff --git a/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs index b9526482875..9aeb77363bb 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs @@ -15,7 +15,7 @@ partial class SqliteDatabaseContextModelSnapshot : ModelSnapshot protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "7.0.7"); + modelBuilder.HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6"); modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => { @@ -113,7 +113,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ByondVersion") .IsRequired() - .HasColumnType("TEXT"); + .HasColumnType("TEXT") + .HasColumnName("EngineVersion"); b.Property("DMApiMajorVersion") .HasColumnType("INTEGER"); @@ -318,7 +319,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("INTEGER"); b.Property("ByondRights") - .HasColumnType("INTEGER"); + .HasColumnType("INTEGER") + .HasColumnName("EngineRights"); b.Property("ChatBotRights") .HasColumnType("INTEGER"); diff --git a/src/Tgstation.Server.Host/Models/CompileJob.cs b/src/Tgstation.Server.Host/Models/CompileJob.cs index 4b43fd049c0..61879a2ef37 100644 --- a/src/Tgstation.Server.Host/Models/CompileJob.cs +++ b/src/Tgstation.Server.Host/Models/CompileJob.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; @@ -30,6 +31,7 @@ public sealed class CompileJob : Api.Models.Internal.CompileJob, IApiTransformab /// The the was made with in string form. /// [Required] + [Column("EngineVersion")] public string ByondVersion { get; set; } /// diff --git a/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs b/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs index af21f7f8513..56604ecaee9 100644 --- a/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs +++ b/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs @@ -1,8 +1,6 @@ using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; using Tgstation.Server.Api.Models.Response; -using Tgstation.Server.Api.Rights; namespace Tgstation.Server.Host.Models { @@ -31,14 +29,6 @@ public sealed class InstancePermissionSet : Api.Models.Internal.InstancePermissi [Required] public PermissionSet PermissionSet { get; set; } - /// - [Column("ByondRights")] - public override EngineRights? EngineRights - { - get => base.EngineRights; - set => base.EngineRights = value; - } - /// public InstancePermissionSetResponse ToApi() => new InstancePermissionSetResponse { From 8834fdb817431b1616cfc6b09026c12a4ad038dc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 21 Oct 2023 12:08:09 -0400 Subject: [PATCH 153/717] Fix failing unit test --- .../Components/Engine/TestOpenDreamInstaller.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs index 72eef95f230..6330ef1b104 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs @@ -40,6 +40,7 @@ static async Task RepoDownloadTest(bool needsClone) var cloneAttempts = 0; var mockRepository = new Mock(); + mockRepository.Setup(x => x.ShaIsParent(It.IsNotNull(), It.IsAny())).ReturnsAsync(true); var mockRepositoryManager = new Mock(); mockRepositoryManager.Setup(x => x.CloneRepository( generalConfig.OpenDreamGitUrl, From be6fe8fa88a8452ec2d52cb3042519e664ec40cf Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 3 Nov 2023 00:34:37 -0400 Subject: [PATCH 154/717] Run systemd as the user `tgstation-server` - Fix .deb build only working in gh-actions tailored environment. - Fix indentation in `rules`. - Fix build script not working fully without a signing key. - Standardize to node 20 as a build dependency. - Fix my ADHD in the `README.md`. Closes #1658 --- .github/CONTRIBUTING.md | 2 +- README.md | 4 +++- build/package/deb/build_package.sh | 20 ++++++++++++++----- build/package/deb/debian/control | 2 +- build/package/deb/debian/postinst | 7 ++++++- build/package/deb/debian/rules | 32 ++++++++++++++++++++---------- build/package/deb/tgs-configure | 4 +--- build/tgstation-server.service | 1 + 8 files changed, 49 insertions(+), 23 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 941aee55759..b8709f641fd 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -34,7 +34,7 @@ You can of course, as always, ask for help at [#coderbus](irc://irc.rizon.net/co ### Development Environment -You need the .NET 8.0 SDK and npm>=v5.7 (in your PATH) to compile the server. +You need the .NET 8.0 SDK, node>=v20, and npm>=v5.7 (in your PATH) to compile the server. The recommended IDE is Visual Studio 2022 or VSCode. diff --git a/README.md b/README.md index a288af1e995..26290b06a11 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,8 @@ sudo dpkg --add-architecture i386 \ && sudo systemctl start tgstation-server ``` +The service will execute as the newly created user: `tgstation-server`. + ##### Debian The `aspnetcore-runtime-8.0` package isn't yet available on mainline Debian and must be [installed from Microsoft](https://learn.microsoft.com/en-us/dotnet/core/install/linux-debian) first. Use the following one-liner to add their packages repository. @@ -143,7 +145,7 @@ The following dependencies are required. [Download the latest release .zip](https://github.com/tgstation/tgstation-server/releases/latest). Choose `ServerConsole`. -If you have SystemD installed, we recommend installing the service unit [here](./build/tgstation-server.service). It assumes TGS is installed into `/opt/tgstation-server` and you will be using the but feel free to adjust it to your needs. Note that the server will need to have it's configuration file setup before running with SystemD. +If you have SystemD installed, we recommend installing the service unit [here](./build/tgstation-server.service). It assumes TGS is installed into `/opt/tgstation-server`, it is executing as the user `tgstation-server`, and you will be using the console runner, but feel free to adjust it to your needs. Note that the server will need to have it's configuration file setup before running with SystemD. Alternatively, to launch the server in the current shell, run `./tgs.sh` in the root of the installation directory. The process will run in a blocking fashion. SIGQUIT will close the server, terminating all live game instances. diff --git a/build/package/deb/build_package.sh b/build/package/deb/build_package.sh index 14dc1a50eda..79f2e57244e 100755 --- a/build/package/deb/build_package.sh +++ b/build/package/deb/build_package.sh @@ -9,16 +9,27 @@ set -x dpkg --add-architecture i386 apt-get update # This package set needs cleanup probably, StackOverflow copypasta -apt-get install -y npm \ +apt-get install -y \ build-essential \ binutils \ lintian \ debhelper \ dh-make \ devscripts \ + ca-certificates \ + curl \ + gnupg \ xmlstarlet # dotnet-sdk-8.0 # Disabled while in preview +# https://github.com/nodesource/distributions +mkdir -p /etc/apt/keyrings +curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg +export NODE_MAJOR=20 +echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list +apt-get update +apt-get install nodejs -y + CURRENT_COMMIT=$(git rev-parse HEAD) rm -rf packaging @@ -56,14 +67,13 @@ set +e if [[ -z "$PACKAGING_KEYGRIP" ]]; then dpkg-buildpackage --no-sign + EXIT_CODE=$? else dpkg-buildpackage --sign-key=$PACKAGING_KEYGRIP --sign-command="$SIGN_COMMAND" + cat /tmp/tgs_wrap_gpg_output.log + EXIT_CODE=$? fi -EXIT_CODE=$? - -cat /tmp/tgs_wrap_gpg_output.log - cd .. exit $EXIT_CODE diff --git a/build/package/deb/debian/control b/build/package/deb/debian/control index 486be1bcf27..a63d1d0fab5 100644 --- a/build/package/deb/debian/control +++ b/build/package/deb/debian/control @@ -5,7 +5,7 @@ Maintainer: Jordan Dominion Rules-Requires-Root: no Build-Depends: debhelper-compat (= 13), - npm, + nodejs, #dotnet-sdk-8.0, Disabled while in preview Standards-Version: 4.6.2 Homepage: https://tgstation.github.io/tgstation-server diff --git a/build/package/deb/debian/postinst b/build/package/deb/debian/postinst index 9f71a1931f2..9a1cb1b13c0 100755 --- a/build/package/deb/debian/postinst +++ b/build/package/deb/debian/postinst @@ -1,9 +1,14 @@ #!/bin/sh -e +adduser --system tgstation-server +mkdir -m 754 -p /var/log/tgstation-server +chown -R tgstation-server /etc/tgstation-server +chown -R tgstation-server /opt/tgstation-server +chown -R tgstation-server /var/log/tgstation-server + #DEBHELPER# if [ "$1" = "configure" ]; then - chmod 600 /etc/tgstation-server deb-systemd-helper stop 'tgstation-server.service' >/dev/null || true echo " _ _ _ _ " diff --git a/build/package/deb/debian/rules b/build/package/deb/debian/rules index a68a2cd7d78..7a13e96dd26 100755 --- a/build/package/deb/debian/rules +++ b/build/package/deb/debian/rules @@ -3,23 +3,23 @@ export DH_VERBOSE = 1 %: - dh $@ + dh $@ override_dh_auto_clean: - rm -rf artifacts - dotnet clean -c ReleaseNoWindows + rm -rf artifacts + dotnet clean -c ReleaseNoWindows override_dh_auto_build: - dotnet restore - cd src/Tgstation.Server.Host.Console && dotnet publish -c Release -o ../../artifacts - cd src/Tgstation.Server.Host && dotnet publish -c Release -o ../../artifacts/lib/Default - rm artifacts/lib/Default/appsettings.yml - build/RemoveUnsupportedRuntimes.sh artifacts/lib/Default - build/RemoveUnsupportedRuntimes.sh artifacts + dotnet restore + cd src/Tgstation.Server.Host.Console && dotnet publish -c Release -o ../../artifacts + cd src/Tgstation.Server.Host && dotnet publish -c Release -o ../../artifacts/lib/Default + rm artifacts/lib/Default/appsettings.yml + build/RemoveUnsupportedRuntimes.sh artifacts/lib/Default + build/RemoveUnsupportedRuntimes.sh artifacts override_dh_auto_install: - cp build/package/deb/MakeInstall ./Makefile - dh_auto_install -- + cp build/package/deb/MakeInstall ./Makefile + dh_auto_install -- override_dh_strip: @@ -27,3 +27,13 @@ override_dh_shlibdeps: override_dh_installsystemd: dh_installsystemd -v --restart-after-upgrade + +override_dh_fixperms: + dh_fixperms + find debian/tgstation-server/opt/tgstation-server -exec chmod 544 {} + + find debian/tgstation-server/opt/tgstation-server -type d -exec chmod 555 {} + + find debian/tgstation-server/opt/tgstation-server/lib -exec chmod 744 {} + + find debian/tgstation-server/opt/tgstation-server/lib -type d -exec chmod 755 {} + + find debian/tgstation-server/etc/tgstation-server -exec chmod 644 {} + + find debian/tgstation-server/etc/tgstation-server -type d -exec chmod 755 {} + + chmod 640 debian/tgstation-server/etc/tgstation-server/appsettings.Production.yml diff --git a/build/package/deb/tgs-configure b/build/package/deb/tgs-configure index 96186f68b07..a4bfd3e5f4c 100755 --- a/build/package/deb/tgs-configure +++ b/build/package/deb/tgs-configure @@ -1,5 +1,3 @@ #!/bin/sh -cd /opt/tgstation-server -export General__SetupWizardMode=Only -exec /usr/bin/dotnet /opt/tgstation-server/lib/Default/Tgstation.Server.Host.dll /tmp/tgs_temp_should_not_be_used --appsettings-base-path=/etc/tgstation-server +exec su -s /bin/sh -c "cd /opt/tgstation-server && export General__SetupWizardMode=Only && exec /usr/bin/dotnet /opt/tgstation-server/lib/Default/Tgstation.Server.Host.dll /tmp/tgs_temp_should_not_be_used --appsettings-base-path=/etc/tgstation-server" tgstation-server diff --git a/build/tgstation-server.service b/build/tgstation-server.service index 83e8e47793d..6f3c087584b 100644 --- a/build/tgstation-server.service +++ b/build/tgstation-server.service @@ -7,6 +7,7 @@ After=postgresql.service After=mssql-server.service [Service] +User=tgstation-server Type=notify-reload NotifyAccess=all WorkingDirectory=/opt/tgstation-server From 0f3fc4a07cbbed5c7c0c5b12f6378e560fdf6b34 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 5 Nov 2023 00:23:04 -0400 Subject: [PATCH 155/717] Address a VS message --- src/Tgstation.Server.Api/Routes.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Api/Routes.cs b/src/Tgstation.Server.Api/Routes.cs index 20b52be7abd..ece56b6876b 100644 --- a/src/Tgstation.Server.Api/Routes.cs +++ b/src/Tgstation.Server.Api/Routes.cs @@ -124,8 +124,7 @@ public static class Routes /// The sanitized path. public static string SanitizeGetPath(string path) { - if (path == null) - path = String.Empty; + path ??= String.Empty; if (path.Length == 0 || path[0] != '/') path = '/' + path; return path; From a01bea5608fe61425316e69068e43a77b7f192f2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 5 Nov 2023 00:29:23 -0400 Subject: [PATCH 156/717] We're officially API breaking! --- build/Version.props | 2 +- .../Controllers/Legacy/ByondController.cs | 345 ------------------ .../Legacy/Models/ByondInstallResponse.cs | 27 -- .../Legacy/Models/ByondResponse.cs | 18 - .../Models/ByondVersionDeleteRequest.cs | 18 - .../Legacy/Models/ByondVersionRequest.cs | 23 -- .../Live/Instance/InstanceTest.cs | 16 - .../Live/Instance/LegacyByondClient.cs | 67 ---- .../Live/Instance/LegacyByondTest.cs | 240 ------------ .../Live/TestLiveServer.cs | 10 - 10 files changed, 1 insertion(+), 765 deletions(-) delete mode 100644 src/Tgstation.Server.Host/Controllers/Legacy/ByondController.cs delete mode 100644 src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondInstallResponse.cs delete mode 100644 src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondResponse.cs delete mode 100644 src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionDeleteRequest.cs delete mode 100644 src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionRequest.cs delete mode 100644 tests/Tgstation.Server.Tests/Live/Instance/LegacyByondClient.cs delete mode 100644 tests/Tgstation.Server.Tests/Live/Instance/LegacyByondTest.cs diff --git a/build/Version.props b/build/Version.props index e186f524adf..5059cb754d7 100644 --- a/build/Version.props +++ b/build/Version.props @@ -5,7 +5,7 @@ 6.0.0 5.0.0 - 9.13.0 + 10.0.0 7.0.0 12.0.0 14.0.0 diff --git a/src/Tgstation.Server.Host/Controllers/Legacy/ByondController.cs b/src/Tgstation.Server.Host/Controllers/Legacy/ByondController.cs deleted file mode 100644 index 2ca7bafb47e..00000000000 --- a/src/Tgstation.Server.Host/Controllers/Legacy/ByondController.cs +++ /dev/null @@ -1,345 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; - -using Tgstation.Server.Api; -using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; -using Tgstation.Server.Api.Models.Response; -using Tgstation.Server.Api.Rights; -using Tgstation.Server.Host.Components; -using Tgstation.Server.Host.Controllers.Legacy.Models; -using Tgstation.Server.Host.Database; -using Tgstation.Server.Host.Extensions; -using Tgstation.Server.Host.Jobs; -using Tgstation.Server.Host.Models; -using Tgstation.Server.Host.Security; -using Tgstation.Server.Host.Transfer; - -namespace Tgstation.Server.Host.Controllers.Legacy -{ - /// - /// Controller for managing BYOND installations. - /// - [Route(Routes.Root + "Byond")] - public sealed class ByondController : InstanceRequiredController - { - /// - /// The for the . - /// - readonly IJobManager jobManager; - - /// - /// The for the . - /// - readonly IFileTransferTicketProvider fileTransferService; - - /// - /// Create an for a given legacy formatted BYOND . - /// - /// The legacy BYOND . - /// A . - static EngineVersion CreateEngineVersionFromLegacyByondVersion(Version version) => new EngineVersion - { - Version = new Version(version.Major, version.Minor), - Engine = EngineType.Byond, - CustomIteration = version.Build <= 0 ? null : version.Build, - }; - - /// - /// Create a legacy formated BYOND for a given . - /// - /// The . - /// A legacy BYOND . - static Version CreateLegacyByondVersionFromEngineVersion(EngineVersion engineVersion) - => new (engineVersion.Version.Major, engineVersion.Version.Minor, engineVersion.CustomIteration ?? 0); - - /// - /// Initializes a new instance of the class. - /// - /// The for the . - /// The for the . - /// The for the . - /// The for the . - /// The value of . - /// The value of . - public ByondController( - IDatabaseContext databaseContext, - IAuthenticationContextFactory authenticationContextFactory, - ILogger logger, - IInstanceManager instanceManager, - IJobManager jobManager, - IFileTransferTicketProvider fileTransferService) - : base( - databaseContext, - authenticationContextFactory, - logger, - instanceManager) - { - this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); - this.fileTransferService = fileTransferService ?? throw new ArgumentNullException(nameof(fileTransferService)); - } - - /// - /// Gets the active . - /// - /// A resulting in the for the operation. - /// Retrieved version information successfully. - [HttpGet] - [TgsAuthorize(EngineRights.ReadActive)] - [ProducesResponseType(typeof(ByondResponse), 200)] - public ValueTask Read() - => WithComponentInstance(instance => - { - var version = instance.EngineManager.ActiveVersion; - return ValueTask.FromResult( - Json(new ByondResponse - { - Version = version?.Engine.Value == EngineType.Byond - ? CreateLegacyByondVersionFromEngineVersion(version) - : null, - })); - }); - - /// - /// Lists installed s. - /// - /// The current page. - /// The page size. - /// The for the operation. - /// A resulting in the for the operation. - /// Retrieved version information successfully. - [HttpGet(Routes.List)] - [TgsAuthorize(EngineRights.ListInstalled)] - [ProducesResponseType(typeof(PaginatedResponse), 200)] - public ValueTask List([FromQuery] int? page, [FromQuery] int? pageSize, CancellationToken cancellationToken) - => WithComponentInstance( - instance => Paginated( - () => ValueTask.FromResult( - new PaginatableResult( - instance - .EngineManager - .InstalledVersions - .Where(x => x.Engine.Value == EngineType.Byond) - .Select(x => new ByondResponse - { - Version = CreateLegacyByondVersionFromEngineVersion(x), - }) - .AsQueryable() - .OrderBy(x => x.Version))), - null, - page, - pageSize, - cancellationToken)); - - /// - /// Changes the active BYOND version to the one specified in a given . - /// - /// The containing the to switch to. - /// The for the operation. - /// A resulting in the for the operation. - /// Switched active version successfully. - /// Created to install and switch active version successfully. - [HttpPost] - [TgsAuthorize(EngineRights.InstallOfficialOrChangeActiveByondVersion | EngineRights.InstallCustomByondVersion)] - [ProducesResponseType(typeof(ByondInstallResponse), 200)] - [ProducesResponseType(typeof(ByondInstallResponse), 202)] -#pragma warning disable CA1506 // TODO: Decomplexify - public async ValueTask Update([FromBody] ByondVersionRequest model, CancellationToken cancellationToken) -#pragma warning restore CA1506 - { - ArgumentNullException.ThrowIfNull(model); - - var uploadingZip = model.UploadCustomZip == true; - - if (model.Version == null - || model.Version.Revision != -1 - || (uploadingZip && model.Version.Build > 0)) - return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); - - var userEngineRights = AuthenticationContext.InstancePermissionSet.EngineRights.Value; - if ((!userEngineRights.HasFlag(EngineRights.InstallOfficialOrChangeActiveByondVersion) && !uploadingZip) - || (!userEngineRights.HasFlag(EngineRights.InstallCustomByondVersion) && uploadingZip)) - return Forbid(); - - // remove cruff fields - var result = new ByondInstallResponse(); - return await WithComponentInstance( - async instance => - { - var byondManager = instance.EngineManager; - var engineVersion = CreateEngineVersionFromLegacyByondVersion(model.Version); - var versionAlreadyInstalled = !uploadingZip - && byondManager - .InstalledVersions - .Any(x => x.Equals(engineVersion)); - if (versionAlreadyInstalled) - { - Logger.LogInformation( - "User ID {userId} changing instance ID {instanceId} BYOND version to {newByondVersion}", - AuthenticationContext.User.Id, - Instance.Id, - engineVersion); - - try - { - await byondManager.ChangeVersion( - null, - engineVersion, - null, - false, - cancellationToken); - } - catch (InvalidOperationException ex) - { - Logger.LogDebug( - ex, - "Race condition: BYOND version {version} uninstalled before we could switch to it. Creating install job instead...", - engineVersion); - versionAlreadyInstalled = false; - } - } - - if (!versionAlreadyInstalled) - { - if (engineVersion.CustomIteration.HasValue) - return BadRequest(new ErrorMessageResponse(ErrorCode.EngineNonExistentCustomVersion)); - - Logger.LogInformation( - "User ID {userId} installing BYOND version to {newByondVersion} on instance ID {instanceId}", - AuthenticationContext.User.Id, - engineVersion, - Instance.Id); - - // run the install through the job manager - var job = new Host.Models.Job - { - Description = $"Install {(!uploadingZip ? string.Empty : "custom ")}BYOND version {engineVersion}", - StartedBy = AuthenticationContext.User, - CancelRightsType = RightsType.Engine, - CancelRight = (ulong)EngineRights.CancelInstall, - Instance = Instance, - }; - - IFileUploadTicket fileUploadTicket = null; - if (uploadingZip) - fileUploadTicket = fileTransferService.CreateUpload(FileUploadStreamKind.None); - - try - { - await jobManager.RegisterOperation( - job, - async (core, databaseContextFactory, paramJob, progressHandler, jobCancellationToken) => - { - Stream zipFileStream = null; - if (fileUploadTicket != null) - await using (fileUploadTicket) - { - var uploadStream = await fileUploadTicket.GetResult(jobCancellationToken) ?? throw new JobException(ErrorCode.FileUploadExpired); - zipFileStream = new MemoryStream(); - try - { - await uploadStream.CopyToAsync(zipFileStream, jobCancellationToken); - } - catch - { - await zipFileStream.DisposeAsync(); - throw; - } - } - - await using (zipFileStream) - await core.EngineManager.ChangeVersion( - progressHandler, - engineVersion, - zipFileStream, - true, - jobCancellationToken); - }, - cancellationToken); - - result.InstallJob = job.ToApi(); - result.FileTicket = fileUploadTicket?.Ticket.FileTicket; - } - catch - { - if (fileUploadTicket != null) - await fileUploadTicket.DisposeAsync(); - - throw; - } - } - - return result.InstallJob != null ? Accepted(result) : Json(result); - }); - } - - /// - /// Attempts to delete the BYOND version specified in a given from the instance. - /// - /// The containing the to delete. - /// The for the operation. - /// A resulting in the for the operation. - /// Created to delete target version successfully. - /// Attempted to delete the active BYOND . - /// The specified was not installed. - [HttpDelete] - [TgsAuthorize(EngineRights.DeleteInstall)] - [ProducesResponseType(typeof(JobResponse), 202)] - [ProducesResponseType(typeof(ErrorMessageResponse), 409)] - [ProducesResponseType(typeof(ErrorMessageResponse), 410)] - public async ValueTask Delete([FromBody] ByondVersionDeleteRequest model, CancellationToken cancellationToken) - { - ArgumentNullException.ThrowIfNull(model); - - if (model.Version == null - || model.Version.Revision != -1) - return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); - - var engineVersion = CreateEngineVersionFromLegacyByondVersion(model.Version); - var notInstalledResponse = await WithComponentInstance( - instance => - { - var engineManager = instance.EngineManager; - - if (engineVersion.Equals(engineManager.ActiveVersion)) - return ValueTask.FromResult( - Conflict(new ErrorMessageResponse(ErrorCode.EngineCannotDeleteActiveVersion))); - - var versionNotInstalled = !engineManager.InstalledVersions.Any(x => x.Equals(engineVersion)); - - return ValueTask.FromResult( - versionNotInstalled - ? this.Gone() - : null); - }); - - if (notInstalledResponse != null) - return notInstalledResponse; - - // run the install through the job manager - var job = new Host.Models.Job - { - Description = $"Delete installed BYOND version {engineVersion}", - StartedBy = AuthenticationContext.User, - CancelRightsType = RightsType.Engine, - CancelRight = (ulong)(engineVersion.CustomIteration.HasValue ? EngineRights.InstallOfficialOrChangeActiveByondVersion : EngineRights.InstallCustomByondVersion), - Instance = Instance, - }; - - await jobManager.RegisterOperation( - job, - (instanceCore, databaseContextFactory, job, progressReporter, jobCancellationToken) - => instanceCore.EngineManager.DeleteVersion(progressReporter, engineVersion, jobCancellationToken), - cancellationToken); - - var apiResponse = job.ToApi(); - return Accepted(apiResponse); - } - } -} diff --git a/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondInstallResponse.cs b/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondInstallResponse.cs deleted file mode 100644 index 5cda990b2c9..00000000000 --- a/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondInstallResponse.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; - -using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Response; - -namespace Tgstation.Server.Host.Controllers.Legacy.Models -{ - /// - /// Represents a BYOND installation job. is used to upload custom BYOND version zip files. - /// - public sealed class ByondInstallResponse : FileTicketResponse - { - /// - /// The being used to install a new . - /// - [ResponseOptions] - public JobResponse InstallJob { get; set; } - - /// - [ResponseOptions] - public override string FileTicket - { - get => base.FileTicket; - set => base.FileTicket = value; - } - } -} diff --git a/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondResponse.cs b/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondResponse.cs deleted file mode 100644 index d541717e8d2..00000000000 --- a/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondResponse.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -using Tgstation.Server.Api.Models; - -namespace Tgstation.Server.Host.Controllers.Legacy.Models -{ - /// - /// Represents an installed BYOND . - /// - public sealed class ByondResponse - { - /// - /// The installed BYOND . BYOND itself only considers the and numbers. This older API uses the number to represent installed custom versions. - /// - [ResponseOptions] - public Version Version { get; set; } - } -} diff --git a/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionDeleteRequest.cs b/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionDeleteRequest.cs deleted file mode 100644 index 9293129298c..00000000000 --- a/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionDeleteRequest.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -using Tgstation.Server.Api.Models; - -namespace Tgstation.Server.Host.Controllers.Legacy.Models -{ - /// - /// A request to delete a specific . - /// - public class ByondVersionDeleteRequest - { - /// - /// The BYOND version to delete. - /// - [RequestOptions(FieldPresence.Required)] - public Version Version { get; set; } - } -} diff --git a/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionRequest.cs b/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionRequest.cs deleted file mode 100644 index 59aebebacc7..00000000000 --- a/src/Tgstation.Server.Host/Controllers/Legacy/Models/ByondVersionRequest.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -using Tgstation.Server.Api.Models; - -namespace Tgstation.Server.Host.Controllers.Legacy.Models -{ - /// - /// A request to install a BYOND . - /// - public sealed class ByondVersionRequest - { - /// - /// The BYOND version to install. - /// - [RequestOptions(FieldPresence.Required)] - public Version Version { get; set; } - - /// - /// If a custom BYOND version is to be uploaded. - /// - public bool? UploadCustomZip { get; set; } - } -} diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index af00d47397a..4601babae0c 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -35,22 +35,6 @@ sealed class InstanceTest(IInstanceManagerClient instanceManagerClient, IFileDow readonly InstanceManager instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager)); readonly ushort serverPort = serverPort; - public async Task RunLegacyByondTest( - IInstanceClient instanceClient, - CancellationToken cancellationToken) - { - var testVersion = await EngineTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); - await new LegacyByondTest( - instanceClient.Jobs, - fileDownloader, - new LegacyByondClient( - (IApiClient)instanceClient.Engine.GetType().GetProperty("ApiClient", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(instanceClient.Engine), - instanceClient.Metadata), - testVersion.Version, - instanceClient.Metadata) - .Run(cancellationToken); - } - public async Task RunTests( IInstanceClient instanceClient, ushort dmPort, diff --git a/tests/Tgstation.Server.Tests/Live/Instance/LegacyByondClient.cs b/tests/Tgstation.Server.Tests/Live/Instance/LegacyByondClient.cs deleted file mode 100644 index 9793401d244..00000000000 --- a/tests/Tgstation.Server.Tests/Live/Instance/LegacyByondClient.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -using Tgstation.Server.Api; -using Tgstation.Server.Api.Models.Response; -using Tgstation.Server.Client; -using Tgstation.Server.Host.Controllers.Legacy.Models; - -namespace Tgstation.Server.Tests.Live.Instance -{ - /// - sealed class LegacyByondClient : PaginatedClient - { - const string Route = Routes.Root + "Byond"; - - /// - /// The for the . - /// - readonly Api.Models.Instance instance; - - /// - /// Initializes a new instance of the class. - /// - /// The for the . - /// The value of . - public LegacyByondClient(IApiClient apiClient, Api.Models.Instance instance) - : base(apiClient) - { - this.instance = instance ?? throw new ArgumentNullException(nameof(instance)); - } - - /// - public ValueTask ActiveVersion(CancellationToken cancellationToken) => ApiClient.Read(Route, instance.Id!.Value, cancellationToken); - - /// - public ValueTask DeleteVersion(ByondVersionDeleteRequest deleteRequest, CancellationToken cancellationToken) - => ApiClient.Delete(Route, deleteRequest, instance.Id!.Value, cancellationToken); - - /// - public ValueTask> InstalledVersions(PaginationSettings paginationSettings, CancellationToken cancellationToken) - => ReadPaged(paginationSettings, Routes.ListRoute(Route), instance.Id, cancellationToken); - - /// - public async ValueTask SetActiveVersion(ByondVersionRequest installRequest, Stream zipFileStream, CancellationToken cancellationToken) - { - if (installRequest == null) - throw new ArgumentNullException(nameof(installRequest)); - if (installRequest.UploadCustomZip == true && zipFileStream == null) - throw new ArgumentNullException(nameof(zipFileStream)); - - var result = await ApiClient.Update( - Route, - installRequest, - instance.Id!.Value, - cancellationToken) - .ConfigureAwait(false); - - if (installRequest.UploadCustomZip == true) - await ApiClient.Upload(result, zipFileStream, cancellationToken).ConfigureAwait(false); - - return result; - } - } -} diff --git a/tests/Tgstation.Server.Tests/Live/Instance/LegacyByondTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/LegacyByondTest.cs deleted file mode 100644 index ef13665456e..00000000000 --- a/tests/Tgstation.Server.Tests/Live/Instance/LegacyByondTest.cs +++ /dev/null @@ -1,240 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using System.Threading; - -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using Moq; - -using Tgstation.Server.Api.Models.Internal; -using Tgstation.Server.Api.Models.Request; -using Tgstation.Server.Api.Models.Response; -using Tgstation.Server.Api.Models; -using Tgstation.Server.Client; -using Tgstation.Server.Common.Extensions; -using Tgstation.Server.Host.Components.Engine; -using Tgstation.Server.Host.Configuration; - -using Tgstation.Server.Host.IO; - -using Tgstation.Server.Host.System; -using Tgstation.Server.Host.Controllers.Legacy.Models; -using Tgstation.Server.Client.Components; - -namespace Tgstation.Server.Tests.Live.Instance -{ - internal class LegacyByondTest : JobsRequiredTest - { - readonly LegacyByondClient byondClient; - readonly Version testVersion; - readonly Api.Models.Instance metadata; - - readonly IFileDownloader fileDownloader; - - public LegacyByondTest(IJobsClient jobsClient, IFileDownloader fileDownloader, LegacyByondClient byondClient, Version testVersion, Api.Models.Instance metadata) - : base(jobsClient) - { - this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader)); - this.byondClient = byondClient ?? throw new ArgumentNullException(nameof(byondClient)); - this.testVersion = testVersion ?? throw new ArgumentNullException(nameof(testVersion)); - this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); - } - - public async Task Run(CancellationToken cancellationToken) - { - await TestNoVersion(cancellationToken); - await TestInstallNullVersion(cancellationToken); - await TestInstallStable(cancellationToken); - await TestInstallFakeVersion(cancellationToken); - await TestCustomInstalls(cancellationToken); - await TestDeletes(cancellationToken); - } - - ValueTask TestInstallNullVersion(CancellationToken cancellationToken) - => ApiAssert.ThrowsException( - () => byondClient.SetActiveVersion( - new ByondVersionRequest(), - null, - cancellationToken), - ErrorCode.ModelValidationFailure); - - async Task TestDeletes(CancellationToken cancellationToken) - { - var deleteThisOneBecauseItWasntPartOfTheOriginalTest = await byondClient.DeleteVersion( - new ByondVersionDeleteRequest - { - Version = new Version(testVersion.Major, testVersion.Minor, 2), - }, cancellationToken); - await WaitForJob(deleteThisOneBecauseItWasntPartOfTheOriginalTest, 30, false, null, cancellationToken); - - var nonExistentUninstallResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( - new ByondVersionDeleteRequest - { - Version = new(509, 1000), - }, - cancellationToken), ErrorCode.ResourceNotPresent); - - var uninstallResponseTask = byondClient.DeleteVersion( - new ByondVersionDeleteRequest - { - Version = testVersion - }, - cancellationToken); - - var badBecauseActiveResponseTask = ApiAssert.ThrowsException(() => byondClient.DeleteVersion( - new ByondVersionDeleteRequest - { - Version = new Version(testVersion.Major, testVersion.Minor, 1), - }, - cancellationToken), ErrorCode.EngineCannotDeleteActiveVersion); - - await badBecauseActiveResponseTask; - - var uninstallJob = await uninstallResponseTask; - Assert.IsNotNull(uninstallJob); - - // Has to wait on deployment test possibly - var uninstallTask = WaitForJob(uninstallJob, 120, false, null, cancellationToken); - - await nonExistentUninstallResponseTask; - - await uninstallTask; - var byondDir = Path.Combine(metadata.Path, "Byond", testVersion.ToString()); - Assert.IsFalse(Directory.Exists(byondDir)); - - var newVersions = await byondClient.InstalledVersions(null, cancellationToken); - Assert.IsNotNull(newVersions); - Assert.AreEqual(1, newVersions.Count); - Assert.AreEqual(new Version(testVersion.Major, testVersion.Minor, 1), newVersions[0].Version); - } - - async Task TestInstallFakeVersion(CancellationToken cancellationToken) - { - var newModel = new ByondVersionRequest - { - Version = new Version(5011, 1385), - }; - - var test = await byondClient.SetActiveVersion(newModel, null, cancellationToken); - Assert.IsNotNull(test.InstallJob); - await WaitForJob(test.InstallJob, 60, true, ErrorCode.EngineDownloadFail, cancellationToken); - } - - async Task TestInstallStable(CancellationToken cancellationToken) - { - var newModel = new ByondVersionRequest - { - Version = testVersion, - }; - var test = await byondClient.SetActiveVersion(newModel, null, cancellationToken); - Assert.IsNotNull(test.InstallJob); - await WaitForJob(test.InstallJob, 180, false, null, cancellationToken); - var currentShit = await byondClient.ActiveVersion(cancellationToken); - Assert.AreEqual(newModel.Version.Semver(), currentShit.Version.Semver()); - - var dreamMaker = "DreamMaker"; - if (new PlatformIdentifier().IsWindows) - dreamMaker += ".exe"; - - var dreamMakerDir = Path.Combine(metadata.Path, "Byond", newModel.Version.ToString(), "byond", "bin"); - - Assert.IsTrue(Directory.Exists(dreamMakerDir), $"Directory {dreamMakerDir} does not exist!"); - Assert.IsTrue( - File.Exists( - Path.Combine(dreamMakerDir, dreamMaker)), - $"Missing DreamMaker executable! Dir contents: {string.Join(", ", Directory.GetFileSystemEntries(dreamMakerDir))}"); - } - - async Task TestNoVersion(CancellationToken cancellationToken) - { - var allVersionsTask = byondClient.InstalledVersions(null, cancellationToken); - var currentShit = await byondClient.ActiveVersion(cancellationToken); - Assert.IsNotNull(currentShit); - Assert.IsNull(currentShit.Version); - var otherShit = await allVersionsTask; - Assert.IsNotNull(otherShit); - Assert.AreEqual(0, otherShit.Count); - } - - async Task TestCustomInstalls(CancellationToken cancellationToken) - { - var generalConfigOptionsMock = new Mock>(); - generalConfigOptionsMock.SetupGet(x => x.Value).Returns(new GeneralConfiguration()); - var sessionConfigOptionsMock = new Mock>(); - sessionConfigOptionsMock.SetupGet(x => x.Value).Returns(new SessionConfiguration()); - - var assemblyInformationProvider = new AssemblyInformationProvider(); - - IEngineInstaller byondInstaller = new PlatformIdentifier().IsWindows - ? new WindowsByondInstaller( - Mock.Of(), - Mock.Of(), - fileDownloader, - generalConfigOptionsMock.Object, - Mock.Of>()) - : new PosixByondInstaller( - Mock.Of(), - Mock.Of(), - fileDownloader, - Mock.Of>()); - - using var windowsByondInstaller = byondInstaller as WindowsByondInstaller; - - // get the bytes for stable - await using var stableBytesMs = await TestingUtils.ExtractMemoryStreamFromInstallationData(await byondInstaller.DownloadVersion(new EngineVersion - { - Version = testVersion, - Engine = EngineType.Byond, - }, null, cancellationToken), cancellationToken); - - var test = await byondClient.SetActiveVersion( - new ByondVersionRequest - { - Version = testVersion, - UploadCustomZip = true, - }, - stableBytesMs, - cancellationToken); - - Assert.IsNotNull(test.InstallJob); - await WaitForJob(test.InstallJob, 30, false, null, cancellationToken); - - // do it again. #1501 - stableBytesMs.Seek(0, SeekOrigin.Begin); - var test2 = await byondClient.SetActiveVersion( - new ByondVersionRequest - { - Version = testVersion, - UploadCustomZip = true, - }, - stableBytesMs, - cancellationToken); - - Assert.IsNotNull(test2.InstallJob); - await WaitForJob(test2.InstallJob, 30, false, null, cancellationToken); - - var newSettings = await byondClient.ActiveVersion(cancellationToken); - Assert.AreEqual(new Version(testVersion.Major, testVersion.Minor, 2), newSettings.Version); - - // test a few switches - var installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest - { - Version = testVersion, - }, null, cancellationToken); - Assert.IsNull(installResponse.InstallJob); - await ApiAssert.ThrowsException(() => byondClient.SetActiveVersion(new ByondVersionRequest - { - Version = new Version(testVersion.Major, testVersion.Minor, 3), - }, null, cancellationToken), ErrorCode.EngineNonExistentCustomVersion); - - installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest - { - Version = new Version(testVersion.Major, testVersion.Minor, 1), - }, null, cancellationToken); - Assert.IsNull(installResponse.InstallJob); - } - } -} diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index fe923e619b7..196b492410e 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1374,15 +1374,6 @@ async Task FailFast(Task task) async Task RunInstanceTests() { - var byondApiCompatTests = FailFast( - instanceTest - .RunLegacyByondTest( - adminClient.Instances.CreateClient(byondApiCompatInstance), - cancellationToken)); - - if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization - await byondApiCompatTests; - async Task ODCompatTests() { var edgeODVersionTask = EngineTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellationToken); @@ -1449,7 +1440,6 @@ await FailFast( await compatTests; await odCompatTests; - await byondApiCompatTests; } var instanceTests = RunInstanceTests(); From 90d41cc88d13a1e011eb0aa1df97f5edf4f7356c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 6 Nov 2023 17:56:03 -0500 Subject: [PATCH 157/717] Replace HTTP 426 with 400 Notable exception is the swarm API, which still uses 426 for version mismatches and would be a pain in the ass to change correctly. Closes #1693 --- docs/API.dox | 1 - src/Tgstation.Server.Client/ApiClient.cs | 5 +++-- src/Tgstation.Server.Host/Controllers/README.md | 1 - .../Extensions/ApplicationBuilderExtensions.cs | 5 +---- src/Tgstation.Server.Host/Security/README.md | 4 ++-- tests/Tgstation.Server.Tests/Live/RawRequestTests.cs | 4 ++-- 6 files changed, 8 insertions(+), 12 deletions(-) diff --git a/docs/API.dox b/docs/API.dox index a859e36c47e..be71673604e 100644 --- a/docs/API.dox +++ b/docs/API.dox @@ -72,7 +72,6 @@ TGS will only every return the response codes listed here - 410: Gone. Attempted to access/modify a resource that ideally should have been ready, but isn't or no longer is - 422: Unprocessable Entity: Used specifically when an operation that requires a server restart is unable to be performed due to the @ref Tgstation.Server.Host.Watchdog not being present in the deployment. Should not happen with a proper server configuration. Response body contains an @ref Tgstation.Server.Api.Models.ErrorMessage - 424: Failed Dependency: When a request that depends on an external API fails for a reason other than rate limiting. The response body will contain an @ref Tgstation.Server.Api.Models.ErrorMessage model detailing the error. -- 426: Upgrade required: Used when the client's API version is not compatible with the server's. Response body contains an @ref Tgstation.Server.Api.Models.ErrorMessage - 429: Rate limited. Used with operations that rely on GitHub.com. If a rate limit is hit for an operation this will be returned. Response will contain a Retry-After header with the amount of seconds to wait. - 500: Server error. Please report the request and response body to the code repository - 501: Not implemented. Functionality not available in the current server version diff --git a/src/Tgstation.Server.Client/ApiClient.cs b/src/Tgstation.Server.Client/ApiClient.cs index 28c5611bddd..3270be8ea28 100644 --- a/src/Tgstation.Server.Client/ApiClient.cs +++ b/src/Tgstation.Server.Client/ApiClient.cs @@ -131,8 +131,6 @@ static void HandleBadResponse(HttpResponseMessage response, string json) #pragma warning restore IDE0066 // Convert switch statement to expression #pragma warning restore IDE0010 // Add missing cases { - case HttpStatusCode.UpgradeRequired: - throw new VersionMismatchException(errorMessage, response); case HttpStatusCode.Unauthorized: throw new UnauthorizedException(errorMessage, response); case HttpStatusCode.InternalServerError: @@ -154,6 +152,9 @@ static void HandleBadResponse(HttpResponseMessage response, string json) case (HttpStatusCode)429: throw new RateLimitException(errorMessage, response); default: + if (errorMessage?.ErrorCode == ErrorCode.ApiMismatch) + throw new VersionMismatchException(errorMessage, response); + throw new ApiConflictException(errorMessage, response); } } diff --git a/src/Tgstation.Server.Host/Controllers/README.md b/src/Tgstation.Server.Host/Controllers/README.md index e1214f91f27..66c5df1244d 100644 --- a/src/Tgstation.Server.Host/Controllers/README.md +++ b/src/Tgstation.Server.Host/Controllers/README.md @@ -7,7 +7,6 @@ Some notable exceptions: - [ApiController](./ApiController.cs) is the base class of nearly all API related controllers. It does the following: - Contains code to deny the request if the instance is not present when it should be. - Contains the `IDatabaseContext` and `ILogger` properties for child controllers. - - Returns 426 Upgrade Required if the API version in the headers are incompatible with the request. - Returns 400 Bad Request if the headers or the PUT/POST'd model is invalid. - Returns 401 If an `IAuthenticationContext` could not be created for a request. - [BridgeController](./BridgeController.cs) is a special controller accessible only from localhost and is used to receive bridge request from DreamDaemon diff --git a/src/Tgstation.Server.Host/Extensions/ApplicationBuilderExtensions.cs b/src/Tgstation.Server.Host/Extensions/ApplicationBuilderExtensions.cs index 55086228dc6..40661c9a5e5 100644 --- a/src/Tgstation.Server.Host/Extensions/ApplicationBuilderExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ApplicationBuilderExtensions.cs @@ -132,11 +132,8 @@ public static void UseApiCompatibility(this IApplicationBuilder applicationBuild var apiHeadersProvider = context.RequestServices.GetRequiredService(); if (apiHeadersProvider.ApiHeaders?.Compatible() == false) { - await new JsonResult( + await new BadRequestObjectResult( new ErrorMessageResponse(ErrorCode.ApiMismatch)) - { - StatusCode = (int)HttpStatusCode.UpgradeRequired, - } .ExecuteResultAsync(new ActionContext { HttpContext = context, diff --git a/src/Tgstation.Server.Host/Security/README.md b/src/Tgstation.Server.Host/Security/README.md index 404b27e1627..ac6cbbc08ff 100644 --- a/src/Tgstation.Server.Host/Security/README.md +++ b/src/Tgstation.Server.Host/Security/README.md @@ -16,7 +16,7 @@ ## For the login request (`POST /`) -1. An attempt to parse the `ApiHeaders` is made. If they were valid, the API version check is performed. If it fails, HTTP 426 with an `ErrorMessageResponse` will be returned. +1. An attempt to parse the `ApiHeaders` is made. If they were valid, the API version check is performed. If it fails, HTTP 400 with an `ErrorMessageResponse` will be returned. 1. If, for some reason, the user attempts to use a JWT to authenticate this request, steps 2-4 of the non-login pipeline list below are performed. 1. The `ApiController` base class inspects the request. - At this point, if the `ApiHeaders` (MINUS the `Authorization` header) cannot be properly parsed, HTTP 400 with an `ErrorMessageResponse` is returned. @@ -51,7 +51,7 @@ ## For all other authenticated requests -1. An attempt to parse the `ApiHeaders` is made. If they were valid. The API version check is performed. If it fails, HTTP 426 with an `ErrorMessageResponse` will be returned. +1. An attempt to parse the `ApiHeaders` is made. If they were valid. The API version check is performed. If it fails, HTTP 400 with an `ErrorMessageResponse` will be returned. 1. The JWT, if present, is validated. If it is, the scope's [AuthenticationContextFactory](./AuthenticationContextFactory.cs) has `SetTokenNbf` called. If not, HTTP 401 will be returned. - Inside ASP.NET Core, this initializes the calling user's identity principal and sets the "sub" claim to the TGS user ID parsed out of the JWT. - We know it's the user ID because we set it up like that in the [TokenFactory](./TokenFactory.cs) diff --git a/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs b/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs index fbf5fe44e56..bf0d409e61a 100644 --- a/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs +++ b/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs @@ -87,7 +87,7 @@ static async Task TestRequestValidation(IServerClient serverClient, Cancellation request.Headers.Add(ApiHeaders.ApiVersionHeader, "Tgstation.Server.Api/6.0.0"); request.Headers.Authorization = new AuthenticationHeaderValue(ApiHeaders.BearerAuthenticationScheme, token); using var response = await httpClient.SendAsync(request, cancellationToken); - Assert.AreEqual(HttpStatusCode.UpgradeRequired, response.StatusCode); + Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode); var content = await response.Content.ReadAsStringAsync(cancellationToken); var message = JsonConvert.DeserializeObject(content); Assert.AreEqual(ErrorCode.ApiMismatch, message.ErrorCode); @@ -101,7 +101,7 @@ static async Task TestRequestValidation(IServerClient serverClient, Cancellation request.Headers.Add(ApiHeaders.ApiVersionHeader, "Tgstation.Server.Api/6.0.0"); request.Headers.Authorization = new AuthenticationHeaderValue(ApiHeaders.BearerAuthenticationScheme, token); using var response = await httpClient.SendAsync(request, cancellationToken); - Assert.AreEqual(HttpStatusCode.UpgradeRequired, response.StatusCode); + Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode); var content = await response.Content.ReadAsStringAsync(cancellationToken); var message = JsonConvert.DeserializeObject(content); Assert.AreEqual(ErrorCode.ApiMismatch, message.ErrorCode); From 2f9fb5df0c66a20960c3472c2dcb45bdbc2980c6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 7 Nov 2023 08:52:01 -0500 Subject: [PATCH 158/717] Suppress the NU5104 while we're in preview Added to #1589 --- src/Tgstation.Server.Client/Tgstation.Server.Client.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj index 375fb7161a4..c946acf8414 100644 --- a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj +++ b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj @@ -7,6 +7,7 @@ Client library for tgstation-server. json web api tgstation-server tgstation ss13 byond client http $(TGS_NUGET_RELEASE_NOTES_CLIENT) + NU5104 From 06dda10ac2a5106cbf793a926909d4b7d8652dc4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 10 Nov 2023 10:04:09 -0500 Subject: [PATCH 159/717] Change the swagger documentation path to `/doc/tgs_api.json` Change hosted site path to `/documentation` Closes #1586 --- .github/workflows/ci-pipeline.yml | 8 ++++---- .../Configuration/GeneralConfiguration.cs | 2 +- src/Tgstation.Server.Host/Core/Application.cs | 11 +++++++++-- .../Utils/SwaggerConfiguration.cs | 7 ++++++- src/Tgstation.Server.Host/appsettings.yml | 2 +- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 4 ++-- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 3a5e143e6ba..123c939f48c 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -478,7 +478,7 @@ jobs: uses: actions/upload-artifact@v3 with: name: openapi-spec - path: C:/swagger.json + path: C:/tgs_api.json - name: Package Server Service if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'Basic' }} @@ -706,7 +706,7 @@ jobs: path: ./swagger - name: Lint OpenAPI Spec - run: npx lint-openapi -v -p -c build/OpenApiValidationSettings.json ./swagger/swagger.json + run: npx lint-openapi -v -p -c build/OpenApiValidationSettings.json ./swagger/tgs_api.json upload-code-coverage: name: Upload Code Coverage @@ -1311,7 +1311,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./swagger/swagger.json + asset_path: ./swagger/tgs_api.json asset_name: swagger.json asset_content_type: application/json @@ -1615,7 +1615,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./swagger/swagger.json + asset_path: ./swagger/tgs_api.json asset_name: swagger.json asset_content_type: application/json diff --git a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs index 7b02f6d177f..1bb02a86e60 100644 --- a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs @@ -108,7 +108,7 @@ public sealed class GeneralConfiguration : ServerInformationBase public bool UseBasicWatchdog { get; set; } /// - /// If the swagger UI should be made avaiable. + /// If the swagger documentation and UI should be made avaiable. /// public bool HostApiDocumentation { get; set; } diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index d730b9de108..4d54a42b014 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -471,8 +471,15 @@ public void Configure( if (generalConfiguration.HostApiDocumentation) { - applicationBuilder.UseSwagger(); - applicationBuilder.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TGS API")); + applicationBuilder.UseSwagger(options => + { + options.RouteTemplate = Routes.Root + "doc/{documentName}.{json|yaml}"; + }); + applicationBuilder.UseSwaggerUI(options => + { + options.RoutePrefix = "documentation"; + options.SwaggerEndpoint(Routes.Root + $"doc/{SwaggerConfiguration.DocumentName}.json", "TGS API"); + }); logger.LogTrace("Swagger API generation enabled"); } diff --git a/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs b/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs index 89f77167329..927fc4f4fa7 100644 --- a/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs +++ b/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs @@ -27,6 +27,11 @@ namespace Tgstation.Server.Host.Utils /// sealed class SwaggerConfiguration : IOperationFilter, IDocumentFilter, ISchemaFilter, IRequestBodyFilter { + /// + /// The name of the swagger document. + /// + public const string DocumentName = "tgs_api"; + /// /// The name for password authentication. /// @@ -51,7 +56,7 @@ sealed class SwaggerConfiguration : IOperationFilter, IDocumentFilter, ISchemaFi public static void Configure(SwaggerGenOptions swaggerGenOptions, string assemblyDocumentationPath, string apiDocumentationPath) { swaggerGenOptions.SwaggerDoc( - "v1", + DocumentName, new OpenApiInfo { Title = "TGS API", diff --git a/src/Tgstation.Server.Host/appsettings.yml b/src/Tgstation.Server.Host/appsettings.yml index bebeb79c043..680c347e3d3 100644 --- a/src/Tgstation.Server.Host/appsettings.yml +++ b/src/Tgstation.Server.Host/appsettings.yml @@ -13,7 +13,7 @@ General: UserGroupLimit: 25 # Maximum number of allowed groups InstanceLimit: 10 # Maximum number of allowed instances ValidInstancePaths: # An array of directories instances may be created in (either directly or as a subdirectory). null removes the restriction - HostApiDocumentation: false # Make HTTP API documentation available at /swagger/v1/swagger.json + HostApiDocumentation: false # Make HTTP API documentation available at /doc/tgs_api.json SkipAddingByondFirewallException: false # Windows Only: Prevent running netsh.exe to add a firewall exception for installed DreamDaemon binaries DeploymentDirectoryCopyTasksPerCore: 100 # Maximum number of concurrent file copy operations PER available CPU core Session: diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 0ef060c2f36..f8cf0c78029 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1302,11 +1302,11 @@ async ValueTask CreateUserWithNoInstancePerms() // Dump swagger to disk // This is purely for CI using var httpClient = new HttpClient(); - var webRequestTask = httpClient.GetAsync(server.Url.ToString() + "swagger/v1/swagger.json", cancellationToken); + var webRequestTask = httpClient.GetAsync(server.Url.ToString() + "doc/tgs_api.json", cancellationToken); using var response = await webRequestTask; response.EnsureSuccessStatusCode(); await using var content = await response.Content.ReadAsStreamAsync(cancellationToken); - await using var output = new FileStream(@"C:\swagger.json", FileMode.Create); + await using var output = new FileStream(@"C:\tgs_api.json", FileMode.Create); await content.CopyToAsync(output, cancellationToken); } From 9e1806a2b4551b9369c80da0235b66e5774b3890 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 10 Nov 2023 12:11:28 -0500 Subject: [PATCH 160/717] Move all API functionality to `/api`. Move `BridgeController` route but BYOND forces us to support the legacy one as well. Add a basic homepage if it's not obvious where to redirect the user. Closes #1689 --- build/Version.props | 2 +- src/DMAPI/tgs/core/core.dm | 4 +- src/DMAPI/tgs/v5/__interop_version.dm | 2 +- src/DMAPI/tgs/v5/api.dm | 12 +- src/DMAPI/tgs/v5/bridge.dm | 4 +- src/Tgstation.Server.Api/Routes.cs | 32 ++--- src/Tgstation.Server.Client/ApiClient.cs | 2 +- src/Tgstation.Server.Client/IServerClient.cs | 2 +- src/Tgstation.Server.Client/ServerClient.cs | 2 +- .../ServerClientFactory.cs | 4 +- ...HomeController.cs => ApiRootController.cs} | 52 +++------ .../Controllers/BridgeController.cs | 11 +- .../Controllers/RootController.cs | 109 ++++++++++++++++++ src/Tgstation.Server.Host/Core/Application.cs | 6 +- .../Swarm/SwarmConstants.cs | 2 +- .../Utils/SwaggerConfiguration.cs | 7 +- .../Views/Root/Index.cshtml | 28 +++++ src/Tgstation.Server.Host/appsettings.yml | 2 +- tests/DMAPI/LongRunning/Test.dm | 30 +++++ .../Live/Instance/TestBridgeHandler.cs | 2 +- .../Live/Instance/WatchdogTest.cs | 10 ++ .../Live/LiveTestingServer.cs | 8 +- .../Live/RawRequestTests.cs | 18 +-- .../Live/TestLiveServer.cs | 57 ++++----- tests/Tgstation.Server.Tests/TestVersions.cs | 27 ++++- 25 files changed, 322 insertions(+), 113 deletions(-) rename src/Tgstation.Server.Host/Controllers/{HomeController.cs => ApiRootController.cs} (90%) create mode 100644 src/Tgstation.Server.Host/Controllers/RootController.cs create mode 100644 src/Tgstation.Server.Host/Views/Root/Index.cshtml diff --git a/build/Version.props b/build/Version.props index e3a0b04745f..5bba820f55e 100644 --- a/build/Version.props +++ b/build/Version.props @@ -10,7 +10,7 @@ 13.0.0 15.0.0 6.6.2 - 5.6.2 + 5.7.0 1.4.0 1.2.1 2.0.0 diff --git a/src/DMAPI/tgs/core/core.dm b/src/DMAPI/tgs/core/core.dm index b9a9f27a28a..4a408e89a23 100644 --- a/src/DMAPI/tgs/core/core.dm +++ b/src/DMAPI/tgs/core/core.dm @@ -42,11 +42,11 @@ var/datum/tgs_version/max_api_version = TgsMaximumApiVersion(); if(version.suite != null && version.minor != null && version.patch != null && version.deprecated_patch != null && version.deprefixed_parameter > max_api_version.deprefixed_parameter) - TGS_ERROR_LOG("Detected unknown API version! Defaulting to latest. Update the DMAPI to fix this problem.") + TGS_ERROR_LOG("Detected unknown Interop API version! Defaulting to latest. Update the DMAPI to fix this problem.") api_datum = /datum/tgs_api/latest if(!api_datum) - TGS_ERROR_LOG("Found unsupported API version: [raw_parameter]. If this is a valid version please report this, backporting is done on demand.") + TGS_ERROR_LOG("Found unsupported Interop API version: [raw_parameter]. If this is a valid version please report this, backporting is done on demand.") return TGS_INFO_LOG("Activating API for version [version.deprefixed_parameter]") diff --git a/src/DMAPI/tgs/v5/__interop_version.dm b/src/DMAPI/tgs/v5/__interop_version.dm index 1b52b31d6a7..83420d130a7 100644 --- a/src/DMAPI/tgs/v5/__interop_version.dm +++ b/src/DMAPI/tgs/v5/__interop_version.dm @@ -1 +1 @@ -"5.6.2" +"5.7.0" diff --git a/src/DMAPI/tgs/v5/api.dm b/src/DMAPI/tgs/v5/api.dm index 7226f29bba6..4a101d58dc1 100644 --- a/src/DMAPI/tgs/v5/api.dm +++ b/src/DMAPI/tgs/v5/api.dm @@ -17,6 +17,8 @@ var/list/chat_channels var/initialized = FALSE + var/initial_bridge_request_received = FALSE + var/datum/tgs_version/interop_version var/chunked_requests = 0 var/list/chunked_topics = list() @@ -25,7 +27,8 @@ /datum/tgs_api/v5/New() . = ..() - TGS_DEBUG_LOG("V5 API created") + interop_version = version + TGS_DEBUG_LOG("V5 API created: [json_encode(args)]") /datum/tgs_api/v5/ApiVersion() return new /datum/tgs_version( @@ -38,7 +41,7 @@ access_identifier = world.params[DMAPI5_PARAM_ACCESS_IDENTIFIER] var/datum/tgs_version/api_version = ApiVersion() - version = null + version = null // we want this to be the TGS version, not the interop version var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands())) if(!istype(bridge_response)) TGS_ERROR_LOG("Failed initial bridge request!") @@ -53,7 +56,8 @@ TGS_INFO_LOG("DMAPI validation, exiting...") TerminateWorld() - version = new /datum/tgs_version(runtime_information[DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION]) + initial_bridge_request_received = TRUE + version = new /datum/tgs_version(runtime_information[DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION]) // reassigning this because it can change if TGS updates security_level = runtime_information[DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL] visibility = runtime_information[DMAPI5_RUNTIME_INFORMATION_VISIBILITY] instance_name = runtime_information[DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME] @@ -105,7 +109,7 @@ /datum/tgs_api/v5/proc/RequireInitialBridgeResponse() TGS_DEBUG_LOG("RequireInitialBridgeResponse()") var/logged = FALSE - while(!version) + while(!initial_bridge_request_received) if(!logged) TGS_DEBUG_LOG("RequireInitialBridgeResponse: Starting sleep") logged = TRUE diff --git a/src/DMAPI/tgs/v5/bridge.dm b/src/DMAPI/tgs/v5/bridge.dm index 37f58bcdf63..8e35dc3b1e3 100644 --- a/src/DMAPI/tgs/v5/bridge.dm +++ b/src/DMAPI/tgs/v5/bridge.dm @@ -48,7 +48,9 @@ var/json = CreateBridgeData(command, data, TRUE) var/encoded_json = url_encode(json) - var/url = "http://127.0.0.1:[server_port]/Bridge?[DMAPI5_BRIDGE_DATA]=[encoded_json]" + var/api_prefix = interop_version.minor >= 7 ? "api/" : "" + + var/url = "http://127.0.0.1:[server_port]/[api_prefix]Bridge?[DMAPI5_BRIDGE_DATA]=[encoded_json]" return url /datum/tgs_api/v5/proc/CreateBridgeData(command, list/data, needs_auth) diff --git a/src/Tgstation.Server.Api/Routes.cs b/src/Tgstation.Server.Api/Routes.cs index b62d7816043..862dd3994e0 100644 --- a/src/Tgstation.Server.Api/Routes.cs +++ b/src/Tgstation.Server.Api/Routes.cs @@ -8,19 +8,19 @@ namespace Tgstation.Server.Api public static class Routes { /// - /// The root controller. + /// The root of API methods. /// - public const string Root = "/"; + public const string ApiRoot = "/api/"; /// /// The root route of all hubs. /// - public const string HubsRoot = Root + "hubs"; + public const string HubsRoot = ApiRoot + "hubs"; /// /// The server administration controller. /// - public const string Administration = Root + "Administration"; + public const string Administration = ApiRoot + "Administration"; /// /// The endpoint to download server logs. @@ -30,32 +30,32 @@ public static class Routes /// /// The user controller. /// - public const string User = Root + "User"; + public const string User = ApiRoot + "User"; /// /// The user group controller. /// - public const string UserGroup = Root + "UserGroup"; + public const string UserGroup = ApiRoot + "UserGroup"; /// /// The controller. /// - public const string InstanceManager = Root + "Instance"; + public const string InstanceManager = ApiRoot + "Instance"; /// /// The BYOND controller. /// - public const string Byond = Root + "Byond"; + public const string Byond = ApiRoot + "Byond"; /// /// The git repository controller. /// - public const string Repository = Root + "Repository"; + public const string Repository = ApiRoot + "Repository"; /// /// The DreamDaemon controller. /// - public const string DreamDaemon = Root + "DreamDaemon"; + public const string DreamDaemon = ApiRoot + "DreamDaemon"; /// /// For accessing DD diagnostics. @@ -65,7 +65,7 @@ public static class Routes /// /// The configuration controller. /// - public const string Configuration = Root + "Config"; + public const string Configuration = ApiRoot + "Config"; /// /// To be paired with for accessing s. @@ -80,27 +80,27 @@ public static class Routes /// /// The instance permission set controller. /// - public const string InstancePermissionSet = Root + "InstancePermissionSet"; + public const string InstancePermissionSet = ApiRoot + "InstancePermissionSet"; /// /// The chat bot controller. /// - public const string Chat = Root + "Chat"; + public const string Chat = ApiRoot + "Chat"; /// /// The deployment controller. /// - public const string DreamMaker = Root + "DreamMaker"; + public const string DreamMaker = ApiRoot + "DreamMaker"; /// /// The jobs controller. /// - public const string Jobs = Root + "Job"; + public const string Jobs = ApiRoot + "Job"; /// /// The transfer controller. /// - public const string Transfer = Root + "Transfer"; + public const string Transfer = ApiRoot + "Transfer"; /// /// The postfix for list operations. diff --git a/src/Tgstation.Server.Client/ApiClient.cs b/src/Tgstation.Server.Client/ApiClient.cs index d759ccbbdd1..f691dd0e905 100644 --- a/src/Tgstation.Server.Client/ApiClient.cs +++ b/src/Tgstation.Server.Client/ApiClient.cs @@ -349,7 +349,7 @@ public async ValueTask RefreshToken(CancellationToken cancellationToken) if (startingToken != headers.Token) return true; - var token = await RunRequest(Routes.Root, new object(), HttpMethod.Post, null, true, cancellationToken).ConfigureAwait(false); + var token = await RunRequest(Routes.ApiRoot, new object(), HttpMethod.Post, null, true, cancellationToken).ConfigureAwait(false); headers = new ApiHeaders(headers.UserAgent!, token); } finally diff --git a/src/Tgstation.Server.Client/IServerClient.cs b/src/Tgstation.Server.Client/IServerClient.cs index 65014f66b1e..317e012ed08 100644 --- a/src/Tgstation.Server.Client/IServerClient.cs +++ b/src/Tgstation.Server.Client/IServerClient.cs @@ -16,7 +16,7 @@ namespace Tgstation.Server.Client public interface IServerClient : IAsyncDisposable { /// - /// The connected server . + /// The connected server's root . /// Uri Url { get; } diff --git a/src/Tgstation.Server.Client/ServerClient.cs b/src/Tgstation.Server.Client/ServerClient.cs index 186e32745b2..6fce35fcf9c 100644 --- a/src/Tgstation.Server.Client/ServerClient.cs +++ b/src/Tgstation.Server.Client/ServerClient.cs @@ -66,7 +66,7 @@ public ServerClient(IApiClient apiClient) public ValueTask DisposeAsync() => apiClient.DisposeAsync(); /// - public ValueTask ServerInformation(CancellationToken cancellationToken) => apiClient.Read(Routes.Root, cancellationToken); + public ValueTask ServerInformation(CancellationToken cancellationToken) => apiClient.Read(Routes.ApiRoot, cancellationToken); /// public void AddRequestLogger(IRequestLogger requestLogger) => apiClient.AddRequestLogger(requestLogger); diff --git a/src/Tgstation.Server.Client/ServerClientFactory.cs b/src/Tgstation.Server.Client/ServerClientFactory.cs index 155198996a2..98a51e8dc5d 100644 --- a/src/Tgstation.Server.Client/ServerClientFactory.cs +++ b/src/Tgstation.Server.Client/ServerClientFactory.cs @@ -138,7 +138,7 @@ public async ValueTask GetServerInformation( if (timeout.HasValue) api.Timeout = timeout.Value; - return await api.Read(Routes.Root, cancellationToken).ConfigureAwait(false); + return await api.Read(Routes.ApiRoot, cancellationToken).ConfigureAwait(false); } /// @@ -169,7 +169,7 @@ async ValueTask CreateWithNewToken( if (timeout.HasValue) api.Timeout = timeout.Value; - token = await api.Update(Routes.Root, cancellationToken).ConfigureAwait(false); + token = await api.Update(Routes.ApiRoot, cancellationToken).ConfigureAwait(false); } var apiHeaders = new ApiHeaders(productHeaderValue, token); diff --git a/src/Tgstation.Server.Host/Controllers/HomeController.cs b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs similarity index 90% rename from src/Tgstation.Server.Host/Controllers/HomeController.cs rename to src/Tgstation.Server.Host/Controllers/ApiRootController.cs index 659a379591d..fbfc1d44659 100644 --- a/src/Tgstation.Server.Host/Controllers/HomeController.cs +++ b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs @@ -32,66 +32,66 @@ namespace Tgstation.Server.Host.Controllers /// /// Root for the . /// - [Route(Routes.Root)] - public sealed class HomeController : ApiController + [Route(Routes.ApiRoot)] + public sealed class ApiRootController : ApiController { /// - /// The for the . + /// The for the . /// readonly ITokenFactory tokenFactory; /// - /// The for the . + /// The for the . /// readonly ISystemIdentityFactory systemIdentityFactory; /// - /// The for the . + /// The for the . /// readonly ICryptographySuite cryptographySuite; /// - /// The for the . + /// The for the . /// readonly IAssemblyInformationProvider assemblyInformationProvider; /// - /// The for the . + /// The for the . /// readonly IIdentityCache identityCache; /// - /// The for the . + /// The for the . /// readonly IOAuthProviders oAuthProviders; /// - /// The for the . + /// The for the . /// readonly IPlatformIdentifier platformIdentifier; /// - /// The for the . + /// The for the . /// readonly ISwarmService swarmService; /// - /// The for the . + /// The for the . /// readonly IServerControl serverControl; /// - /// The for the . + /// The for the . /// readonly GeneralConfiguration generalConfiguration; /// - /// The for the . + /// The for the . /// readonly ControlPanelConfiguration controlPanelConfiguration; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The for the . /// The for the . @@ -108,7 +108,7 @@ public sealed class HomeController : ApiController /// The containing the value of . /// The for the . /// The for the . - public HomeController( + public ApiRootController( IDatabaseContext databaseContext, IAuthenticationContext authenticationContext, ITokenFactory tokenFactory, @@ -122,7 +122,7 @@ public HomeController( IServerControl serverControl, IOptions generalConfigurationOptions, IOptions controlPanelConfigurationOptions, - ILogger logger, + ILogger logger, IApiHeadersProvider apiHeadersProvider) : base( databaseContext, @@ -154,29 +154,12 @@ public HomeController( [HttpGet] [AllowAnonymous] [ProducesResponseType(typeof(ServerInformationResponse), 200)] -#pragma warning disable CA1506 - public IActionResult Home() + public IActionResult ServerInfo() { - if (controlPanelConfiguration.Enable) - Response.Headers.Add( - HeaderNames.Vary, - new StringValues(ApiHeaders.ApiVersionHeader)); - // if they tried to authenticate in any form and failed, let them know immediately bool failIfUnauthed; if (ApiHeaders == null) { - if (controlPanelConfiguration.Enable && !Request.Headers.TryGetValue(ApiHeaders.ApiVersionHeader, out _)) - { - Logger.LogDebug("No API headers on request, redirecting to control panel..."); - - var controlPanelRoute = controlPanelConfiguration.PublicPath; - if (String.IsNullOrWhiteSpace(controlPanelRoute)) - controlPanelRoute = ControlPanelController.ControlPanelRoute; - - return Redirect(controlPanelRoute); - } - try { // we only allow authorization header issues @@ -211,7 +194,6 @@ public IActionResult Home() UpdateInProgress = serverControl.UpdateInProgress, }); } -#pragma warning restore CA1506 /// /// Attempt to authenticate a using . diff --git a/src/Tgstation.Server.Host/Controllers/BridgeController.cs b/src/Tgstation.Server.Host/Controllers/BridgeController.cs index 4ae2e0497c8..86d67d19c05 100644 --- a/src/Tgstation.Server.Host/Controllers/BridgeController.cs +++ b/src/Tgstation.Server.Host/Controllers/BridgeController.cs @@ -8,9 +8,12 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; + using Newtonsoft.Json; + using Serilog.Context; +using Tgstation.Server.Api; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.Utils; @@ -20,10 +23,16 @@ namespace Tgstation.Server.Host.Controllers /// /// for recieving DMAPI requests from DreamDaemon. /// - [Route("/Bridge")] + [Route("/" + RouteExtension)] // obsolete route, but BYOND can't handle a simple fucking 301 + [Route(Routes.ApiRoot + RouteExtension)] [ApiExplorerSettings(IgnoreApi = true)] public sealed class BridgeController : ApiControllerBase { + /// + /// The route to the . + /// + const string RouteExtension = "Bridge"; + /// /// If the content of bridge requests and responses should be logged. /// diff --git a/src/Tgstation.Server.Host/Controllers/RootController.cs b/src/Tgstation.Server.Host/Controllers/RootController.cs new file mode 100644 index 00000000000..fd1bf36b112 --- /dev/null +++ b/src/Tgstation.Server.Host/Controllers/RootController.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; + +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; + +using Tgstation.Server.Host.Configuration; +using Tgstation.Server.Host.System; +using Tgstation.Server.Host.Utils; + +namespace Tgstation.Server.Host.Controllers +{ + /// + /// The root path . + /// + [Route("/")] + public sealed class RootController : Controller + { + /// + /// The route to the TGS logo .svg in the on Windows. + /// + public const string ProjectLogoSvgRouteWindows = "/0176d5d8b7d307f158e0.svg"; + + /// + /// The route to the TGS logo .svg in the on Linux. + /// + public const string ProjectLogoSvgRouteLinux = "/b5616c99bf2052a6bbd7.svg"; + + /// + /// The for the . + /// + readonly IAssemblyInformationProvider assemblyInformationProvider; + + /// + /// The for the . + /// + readonly IPlatformIdentifier platformIdentifier; + + /// + /// The for the . + /// + readonly GeneralConfiguration generalConfiguration; + + /// + /// The for the . + /// + readonly ControlPanelConfiguration controlPanelConfiguration; + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + /// The containing the value of . + /// The containing the value of . + public RootController( + IAssemblyInformationProvider assemblyInformationProvider, + IPlatformIdentifier platformIdentifier, + IOptions generalConfigurationOptions, + IOptions controlPanelConfigurationOptions) + { + this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); + this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); + generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); + controlPanelConfiguration = controlPanelConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(controlPanelConfigurationOptions)); + } + + /// + /// Gets the server's homepage. + /// + /// The appropriate . + [HttpGet] + [AllowAnonymous] + public IActionResult Index() + { + const string ApiDocumentationRoute = "/" + SwaggerConfiguration.DocumentationSiteRouteExtension; + var panelEnabled = controlPanelConfiguration.Enable; + var apiDocsEnabled = generalConfiguration.HostApiDocumentation; + + if (panelEnabled ^ apiDocsEnabled) + if (panelEnabled) + return Redirect(ControlPanelController.ControlPanelRoute); + else + return Redirect(ApiDocumentationRoute); + + Dictionary links; + if (panelEnabled) + links = new Dictionary() + { + { "Web Control Panel", ControlPanelController.ControlPanelRoute.TrimStart('/') }, + { "API Documentation", SwaggerConfiguration.DocumentationSiteRouteExtension }, + }; + else + links = null; + + var model = new + { + Links = links, + Svg = platformIdentifier.IsWindows // these are different because of motherfucking line endings -_- + ? ProjectLogoSvgRouteWindows + : ProjectLogoSvgRouteLinux, + Title = assemblyInformationProvider.VersionString, + }; + + return View(model); + } + } +} diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 4d54a42b014..c3a4907f281 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -473,12 +473,12 @@ public void Configure( { applicationBuilder.UseSwagger(options => { - options.RouteTemplate = Routes.Root + "doc/{documentName}.{json|yaml}"; + options.RouteTemplate = Routes.ApiRoot + "doc/{documentName}.{json|yaml}"; }); applicationBuilder.UseSwaggerUI(options => { - options.RoutePrefix = "documentation"; - options.SwaggerEndpoint(Routes.Root + $"doc/{SwaggerConfiguration.DocumentName}.json", "TGS API"); + options.RoutePrefix = SwaggerConfiguration.DocumentationSiteRouteExtension; + options.SwaggerEndpoint(Routes.ApiRoot + $"doc/{SwaggerConfiguration.DocumentName}.json", "TGS API"); }); logger.LogTrace("Swagger API generation enabled"); } diff --git a/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs b/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs index fe2b892c327..f5485cc2805 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs @@ -14,7 +14,7 @@ static class SwarmConstants /// /// The base route for . /// - public const string ControllerRoute = Routes.Root + "Swarm"; + public const string ControllerRoute = Routes.ApiRoot + "Swarm"; /// /// The header used to pass in the . diff --git a/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs b/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs index 927fc4f4fa7..8f8b0195bd7 100644 --- a/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs +++ b/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs @@ -32,6 +32,11 @@ sealed class SwaggerConfiguration : IOperationFilter, IDocumentFilter, ISchemaFi /// public const string DocumentName = "tgs_api"; + /// + /// The path to the hosted documentation site. + /// + public const string DocumentationSiteRouteExtension = "documentation"; + /// /// The name for password authentication. /// @@ -410,7 +415,7 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) twoHundredResponseContents.Add(MediaTypeNames.Application.Octet, fileContent); } } - else if (context.MethodInfo.Name == nameof(HomeController.CreateToken)) + else if (context.MethodInfo.Name == nameof(ApiRootController.CreateToken)) { var passwordScheme = new OpenApiSecurityScheme { diff --git a/src/Tgstation.Server.Host/Views/Root/Index.cshtml b/src/Tgstation.Server.Host/Views/Root/Index.cshtml new file mode 100644 index 00000000000..209a6ad5ac9 --- /dev/null +++ b/src/Tgstation.Server.Host/Views/Root/Index.cshtml @@ -0,0 +1,28 @@ +@{ + var svgPath = Model.Svg; + var title = Model.Title; + + + + @title + + + + + @{ + if (Model.Links != null) + foreach (KeyValuePair kvp in Model.Links) + { +

+ @kvp.Key +

+ } + } + + +} diff --git a/src/Tgstation.Server.Host/appsettings.yml b/src/Tgstation.Server.Host/appsettings.yml index 680c347e3d3..4ea862d7da8 100644 --- a/src/Tgstation.Server.Host/appsettings.yml +++ b/src/Tgstation.Server.Host/appsettings.yml @@ -13,7 +13,7 @@ General: UserGroupLimit: 25 # Maximum number of allowed groups InstanceLimit: 10 # Maximum number of allowed instances ValidInstancePaths: # An array of directories instances may be created in (either directly or as a subdirectory). null removes the restriction - HostApiDocumentation: false # Make HTTP API documentation available at /doc/tgs_api.json + HostApiDocumentation: false # Make HTTP API documentation available at /api/doc/tgs_api.json SkipAddingByondFirewallException: false # Windows Only: Prevent running netsh.exe to add a firewall exception for installed DreamDaemon binaries DeploymentDirectoryCopyTasksPerCore: 100 # Maximum number of concurrent file copy operations PER available CPU core Session: diff --git a/tests/DMAPI/LongRunning/Test.dm b/tests/DMAPI/LongRunning/Test.dm index c2e274f4d41..c9cbf5cab11 100644 --- a/tests/DMAPI/LongRunning/Test.dm +++ b/tests/DMAPI/LongRunning/Test.dm @@ -180,6 +180,11 @@ var/run_bridge_test kajigger_test = TRUE return "we love casting spells" + var/its_sad = data["im_out_of_memes"] + if(its_sad) + TestLegacyBridge() + return "yeah gimmie a sec" + TgsChatBroadcast(new /datum/tgs_message_content("Recieved non-tgs topic: `[T]`")) return "feck" @@ -349,3 +354,28 @@ var/suppress_bridge_spam = FALSE FailTest("Failed to end bridge limit test! [(istype(final_result) ? json_encode(final_result): (final_result || "null"))]") api.access_identifier = old_ai + +/proc/TestLegacyBridge() + set waitfor = FALSE + + sleep(10) + + var/datum/tgs_api/v5/api = TGS_READ_GLOBAL(tgs) + if(api.interop_version.suite != 5) + FailTest("Legacy bridge test not required anymore?") + + var/old_minor_version = api.interop_version.minor + api.interop_version.minor = 6 // before api repath + + var/result + var/bridge_request = api.CreateBridgeRequest(5, list("chatMessage" = list("text" = "legacy bridge test", "channelIds" = list()))) + try + result = api.PerformBridgeRequest(bridge_request) + catch(var/exception/e2) + world.log << "Caught exception: [e2]" + result = null + + if(!result || lastTgsError) + FailTest("Failed bridge request redirect test!") + + api.interop_version.minor = old_minor_version diff --git a/tests/Tgstation.Server.Tests/Live/Instance/TestBridgeHandler.cs b/tests/Tgstation.Server.Tests/Live/Instance/TestBridgeHandler.cs index 53e0c43a517..4276067b192 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/TestBridgeHandler.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/TestBridgeHandler.cs @@ -88,7 +88,7 @@ public async ValueTask ProcessBridgeRequest(BridgeParameters par Assert.AreEqual("payload", coreMessage); var serializedRequest = JsonConvert.SerializeObject(parameters, DMApiConstants.SerializerSettings); - var actualLastRequest = $"http://127.0.0.1:{serverPort}/Bridge?data=" + HttpUtility.UrlEncode(serializedRequest); + var actualLastRequest = $"http://127.0.0.1:{serverPort}/api/Bridge?data=" + HttpUtility.UrlEncode(serializedRequest); lastBridgeRequestSize = actualLastRequest.Length; return new BridgeResponseHack { diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 0a67dc8c029..7c64451fd14 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -219,6 +219,8 @@ async Task InteropTestsForLongRunningDme(CancellationToken cancellationToken) await RegressionTest1550(cancellationToken); + await TestLegacyBridgeEndpoint(cancellationToken); + var deleteJobTask = TestDeleteByondInstallErrorCasesAndQueing(cancellationToken); SessionController.LogTopicRequests = false; @@ -1299,5 +1301,13 @@ async Task CheckDMApiFail(CompileJobResponse compileJob, CancellationToken cance var logtext = await File.ReadAllTextAsync(logfile.FullName, cancellationToken); Assert.IsFalse(String.IsNullOrWhiteSpace(logtext)); } + + async ValueTask TestLegacyBridgeEndpoint(CancellationToken cancellationToken) + { + var result = await topicClient.SendTopic(IPAddress.Loopback, "im_out_of_memes=1", ddPort, cancellationToken); + Assert.AreEqual("yeah gimmie a sec", result.StringData); + await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken); + await CheckDMApiFail((await instanceClient.DreamDaemon.Read(cancellationToken)).ActiveCompileJob, cancellationToken); + } } } diff --git a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs index 5f78b526b16..f43798005fb 100644 --- a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs +++ b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; +using Tgstation.Server.Api; using Tgstation.Server.Api.Models; using Tgstation.Server.Host; using Tgstation.Server.Host.Configuration; @@ -50,7 +51,9 @@ static async Task Cleanup(string directory) } } - public Uri Url { get; } + public Uri ApiUrl { get; } + + public Uri RootUrl { get; } public string Directory { get; } @@ -82,7 +85,8 @@ public LiveTestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth Directory = Path.Combine(Directory, Guid.NewGuid().ToString()); System.IO.Directory.CreateDirectory(Directory); string urlString = $"http://localhost:{port}"; - Url = new Uri(urlString); + RootUrl = new Uri(urlString); + ApiUrl = new Uri(urlString + Routes.ApiRoot); //so we need a db //we have to rely on env vars diff --git a/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs b/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs index bf0d409e61a..50e9b211692 100644 --- a/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs +++ b/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs @@ -37,7 +37,7 @@ static async Task TestRequestValidation(IServerClient serverClient, Cancellation var token = serverClient.Token.Bearer; // check that 400s are returned appropriately using var httpClient = new HttpClient(); - using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString())) + using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString() + Routes.ApiRoot.TrimStart('/'))) { request.Headers.Accept.Clear(); request.Headers.UserAgent.Add(new ProductInfoHeaderValue("RootTest", "1.0.0")); @@ -45,7 +45,7 @@ static async Task TestRequestValidation(IServerClient serverClient, Cancellation Assert.AreEqual(HttpStatusCode.NotAcceptable, response.StatusCode); } - using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString())) + using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString() + Routes.ApiRoot.TrimStart('/'))) { request.Headers.Accept.Clear(); request.Headers.UserAgent.Add(new ProductInfoHeaderValue("RootTest", "1.0.0")); @@ -54,7 +54,7 @@ static async Task TestRequestValidation(IServerClient serverClient, Cancellation Assert.AreEqual(HttpStatusCode.NotAcceptable, response.StatusCode); } - using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString())) + using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString() + Routes.ApiRoot.TrimStart('/'))) { request.Headers.Accept.Clear(); request.Headers.UserAgent.Add(new ProductInfoHeaderValue("RootTest", "1.0.0")); @@ -66,7 +66,7 @@ static async Task TestRequestValidation(IServerClient serverClient, Cancellation Assert.AreEqual(ErrorCode.BadHeaders, message.ErrorCode); } - using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString())) + using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString() + Routes.ApiRoot.TrimStart('/'))) { request.Headers.Accept.Clear(); request.Headers.UserAgent.Add(new ProductInfoHeaderValue("RootTest", "1.0.0")); @@ -79,7 +79,7 @@ static async Task TestRequestValidation(IServerClient serverClient, Cancellation Assert.AreEqual(ApiHeaders.Version, message.ApiVersion); } - using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString())) + using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString() + Routes.ApiRoot.TrimStart('/'))) { request.Headers.Accept.Clear(); request.Headers.UserAgent.Add(new ProductInfoHeaderValue("RootTest", "1.0.0")); @@ -149,7 +149,7 @@ static async Task TestRequestValidation(IServerClient serverClient, Cancellation Assert.AreEqual(ErrorCode.InstanceHeaderRequired, message.ErrorCode); } - using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString())) + using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString() + Routes.ApiRoot.TrimStart('/'))) { request.Headers.Accept.Clear(); request.Headers.UserAgent.Add(new ProductInfoHeaderValue("RootTest", "1.0.0")); @@ -163,7 +163,7 @@ static async Task TestRequestValidation(IServerClient serverClient, Cancellation Assert.AreEqual(ErrorCode.BadHeaders, message.ErrorCode); } - using (var request = new HttpRequestMessage(HttpMethod.Post, url.ToString())) + using (var request = new HttpRequestMessage(HttpMethod.Post, url.ToString() + Routes.ApiRoot.TrimStart('/'))) { request.Headers.Accept.Clear(); request.Headers.UserAgent.Add(new ProductInfoHeaderValue("RootTest", "1.0.0")); @@ -178,7 +178,7 @@ static async Task TestRequestValidation(IServerClient serverClient, Cancellation Assert.AreEqual(ErrorCode.BadHeaders, message.ErrorCode); } - using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString())) + using (var request = new HttpRequestMessage(HttpMethod.Get, url.ToString() + Routes.ApiRoot.TrimStart('/'))) { request.Headers.Accept.Clear(); request.Headers.UserAgent.Add(new ProductInfoHeaderValue("RootTest", "1.0.0")); @@ -232,7 +232,7 @@ static async Task TestOAuthFails(IServerClient serverClient, CancellationToken c // just hitting each type of oauth provider for coverage foreach (var I in Enum.GetValues(typeof(OAuthProvider))) - using (var request = new HttpRequestMessage(HttpMethod.Post, url.ToString())) + using (var request = new HttpRequestMessage(HttpMethod.Post, url.ToString() + Routes.ApiRoot.TrimStart('/'))) { request.Headers.Accept.Clear(); request.Headers.UserAgent.Add(new ProductInfoHeaderValue("RootTest", "1.0.0")); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index f8cf0c78029..3daea816f76 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -255,11 +255,11 @@ async ValueTask TestWithoutAndWithPermission(Func( () => adminClient.Administration.Update( new ServerUpdateRequest @@ -442,7 +442,7 @@ public async Task TestOneServerSwarmUpdate() try { - await using var controllerClient = await CreateAdminClient(controller.Url, cancellationToken); + await using var controllerClient = await CreateAdminClient(controller.ApiUrl, cancellationToken); var controllerInfo = await controllerClient.ServerInformation(cancellationToken); @@ -544,9 +544,9 @@ public async Task TestSwarmSynchronizationAndUpdates() try { - await using var controllerClient = await CreateAdminClient(controller.Url, cancellationToken); - await using var node1Client = await CreateAdminClient(node1.Url, cancellationToken); - await using var node2Client = await CreateAdminClient(node2.Url, cancellationToken); + await using var controllerClient = await CreateAdminClient(controller.ApiUrl, cancellationToken); + await using var node1Client = await CreateAdminClient(node1.ApiUrl, cancellationToken); + await using var node2Client = await CreateAdminClient(node2.ApiUrl, cancellationToken); var controllerInfo = await controllerClient.ServerInformation(cancellationToken); @@ -615,7 +615,7 @@ await Task.WhenAny( newUser.Name, "asdfasdfasdfasdf"); - await using var node1BadClient = clientFactory.CreateFromToken(node1.Url, controllerUserClient.Token); + await using var node1BadClient = clientFactory.CreateFromToken(node1.RootUrl, controllerUserClient.Token); await ApiAssert.ThrowsException(() => node1BadClient.Administration.Read(cancellationToken)); // check instance info is not shared @@ -685,8 +685,8 @@ void CheckServerUpdated(LiveTestingServer server) controller.Run(cancellationToken).AsTask(), node1.Run(cancellationToken).AsTask()); - await using var controllerClient2 = await CreateAdminClient(controller.Url, cancellationToken); - await using var node1Client2 = await CreateAdminClient(node1.Url, cancellationToken); + await using var controllerClient2 = await CreateAdminClient(controller.ApiUrl, cancellationToken); + await using var node1Client2 = await CreateAdminClient(node1.ApiUrl, cancellationToken); await ApiAssert.ThrowsException(() => controllerClient2.Administration.Update( new ServerUpdateRequest @@ -701,7 +701,7 @@ await ApiAssert.ThrowsException(() = serverTask, node2.Run(cancellationToken).AsTask()); - await using var node2Client2 = await CreateAdminClient(node2.Url, cancellationToken); + await using var node2Client2 = await CreateAdminClient(node2.ApiUrl, cancellationToken); async Task WaitForSwarmServerUpdate2() { @@ -815,9 +815,9 @@ public async Task TestSwarmReconnection() try { - await using var controllerClient = await CreateAdminClient(controller.Url, cancellationToken); - await using var node1Client = await CreateAdminClient(node1.Url, cancellationToken); - await using var node2Client = await CreateAdminClient(node2.Url, cancellationToken); + await using var controllerClient = await CreateAdminClient(controller.ApiUrl, cancellationToken); + await using var node1Client = await CreateAdminClient(node1.ApiUrl, cancellationToken); + await using var node2Client = await CreateAdminClient(node2.ApiUrl, cancellationToken); var controllerInfo = await controllerClient.ServerInformation(cancellationToken); @@ -897,7 +897,7 @@ await Task.WhenAny( Assert.IsTrue(controllerTask.IsCompleted); controllerTask = controller.Run(cancellationToken).AsTask(); - await using var controllerClient2 = await CreateAdminClient(controller.Url, cancellationToken); + await using var controllerClient2 = await CreateAdminClient(controller.ApiUrl, cancellationToken); // node 2 should reconnect once it's health check triggers await Task.WhenAny( @@ -934,7 +934,7 @@ await ApiAssert.ThrowsException( ErrorCode.SwarmIntegrityCheckFailed); node2Task = node2.Run(cancellationToken).AsTask(); - await using var node2Client2 = await CreateAdminClient(node2.Url, cancellationToken); + await using var node2Client2 = await CreateAdminClient(node2.ApiUrl, cancellationToken); // should re-register await Task.WhenAny( @@ -991,7 +991,7 @@ async ValueTask TestTgstation(bool interactive) var serverTask = server.Run(cancellationToken); try { - await using var adminClient = await CreateAdminClient(server.Url, cancellationToken); + await using var adminClient = await CreateAdminClient(server.ApiUrl, cancellationToken); var instanceManagerTest = new InstanceManagerTest(adminClient, server.Directory); var instance = await instanceManagerTest.CreateTestInstance("TgTestInstance", cancellationToken); @@ -1273,7 +1273,7 @@ async Task TestTgsInternal(CancellationToken hardCancellationToken) { Api.Models.Instance instance; long initialStaged, initialActive; - await using var firstAdminClient = await CreateAdminClient(server.Url, cancellationToken); + await using var firstAdminClient = await CreateAdminClient(server.ApiUrl, cancellationToken); async ValueTask CreateUserWithNoInstancePerms() { @@ -1291,7 +1291,7 @@ async ValueTask CreateUserWithNoInstancePerms() var user = await firstAdminClient.Users.Create(createRequest, cancellationToken); Assert.IsTrue(user.Enabled); - return await clientFactory.CreateFromLogin(server.Url, createRequest.Name, createRequest.Password, cancellationToken: cancellationToken); + return await clientFactory.CreateFromLogin(server.RootUrl, createRequest.Name, createRequest.Password, cancellationToken: cancellationToken); } var jobsHubTest = new JobsHubTests(firstAdminClient, await CreateUserWithNoInstancePerms()); @@ -1302,7 +1302,7 @@ async ValueTask CreateUserWithNoInstancePerms() // Dump swagger to disk // This is purely for CI using var httpClient = new HttpClient(); - var webRequestTask = httpClient.GetAsync(server.Url.ToString() + "doc/tgs_api.json", cancellationToken); + var webRequestTask = httpClient.GetAsync(server.ApiUrl.ToString() + "doc/tgs_api.json", cancellationToken); using var response = await webRequestTask; response.EnsureSuccessStatusCode(); await using var content = await response.Content.ReadAsStreamAsync(cancellationToken); @@ -1343,7 +1343,7 @@ async Task FailFast(Task task) firstAdminClient.Instances, fileDownloader, GetInstanceManager(), - (ushort)server.Url.Port); + (ushort)server.ApiUrl.Port); async Task RunInstanceTests() { @@ -1415,7 +1415,7 @@ await FailFast( using var blockingSocket = new Socket(SocketType.Stream, ProtocolType.Tcp); blockingSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true); blockingSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); - blockingSocket.Bind(new IPEndPoint(IPAddress.Any, server.Url.Port)); + blockingSocket.Bind(new IPEndPoint(IPAddress.Any, server.ApiUrl.Port)); // bind test run await server.Run(cancellationToken); Assert.Fail("Expected server task to end with a SocketException"); @@ -1437,7 +1437,7 @@ await FailFast( // chat bot start and DD reattach test serverTask = server.Run(cancellationToken).AsTask(); - await using (var adminClient = await CreateAdminClient(server.Url, cancellationToken)) + await using (var adminClient = await CreateAdminClient(server.ApiUrl, cancellationToken)) { await jobsHubTest.WaitForReconnect(cancellationToken); var instanceClient = adminClient.Instances.CreateClient(instance); @@ -1541,7 +1541,7 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) serverTask = server.Run(cancellationToken).AsTask(); long expectedCompileJobId, expectedStaged; var edgeByond = await ByondTest.GetEdgeVersion(fileDownloader, cancellationToken); - await using (var adminClient = await CreateAdminClient(server.Url, cancellationToken)) + await using (var adminClient = await CreateAdminClient(server.ApiUrl, cancellationToken)) { var instanceClient = adminClient.Instances.CreateClient(instance); await WaitForInitialJobs(instanceClient); @@ -1552,7 +1552,7 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value); var compileJob = await instanceClient.DreamMaker.Compile(cancellationToken); - var wdt = new WatchdogTest(edgeByond, instanceClient, GetInstanceManager(), (ushort)server.Url.Port, server.HighPriorityDreamDaemon, mainDDPort, server.UsingBasicWatchdog); + var wdt = new WatchdogTest(edgeByond, instanceClient, GetInstanceManager(), (ushort)server.ApiUrl.Port, server.HighPriorityDreamDaemon, mainDDPort, server.UsingBasicWatchdog); await wdt.WaitForJob(compileJob, 30, false, null, cancellationToken); dd = await instanceClient.DreamDaemon.Read(cancellationToken); @@ -1590,7 +1590,7 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest // post/entity deletion tests serverTask = server.Run(cancellationToken).AsTask(); - await using (var adminClient = await CreateAdminClient(server.Url, cancellationToken)) + await using (var adminClient = await CreateAdminClient(server.ApiUrl, cancellationToken)) { var instanceClient = adminClient.Instances.CreateClient(instance); await WaitForInitialJobs(instanceClient); @@ -1601,7 +1601,7 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest Assert.AreEqual(WatchdogStatus.Online, currentDD.Status); Assert.AreEqual(expectedStaged, currentDD.StagedCompileJob.Job.Id.Value); - var wdt = new WatchdogTest(edgeByond, instanceClient, GetInstanceManager(), (ushort)server.Url.Port, server.HighPriorityDreamDaemon, mainDDPort, server.UsingBasicWatchdog); + var wdt = new WatchdogTest(edgeByond, instanceClient, GetInstanceManager(), (ushort)server.ApiUrl.Port, server.HighPriorityDreamDaemon, mainDDPort, server.UsingBasicWatchdog); currentDD = await wdt.TellWorldToReboot(cancellationToken); Assert.AreEqual(expectedStaged, currentDD.ActiveCompileJob.Job.Id.Value); Assert.IsNull(currentDD.StagedCompileJob); @@ -1644,6 +1644,7 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest async Task CreateAdminClient(Uri url, CancellationToken cancellationToken) { + url = new Uri(url.ToString().Replace(Routes.ApiRoot, String.Empty)); var giveUpAt = DateTimeOffset.UtcNow.AddMinutes(2); for (var I = 1; ; ++I) { diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 41c48a1196d..68ac407ef69 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -1,9 +1,11 @@ using System; using System.IO; using System.IO.Compression; +using System.Globalization; using System.Linq; using System.Net.Http; using System.Reflection; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; @@ -27,7 +29,7 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; -using System.Net; +using Tgstation.Server.Host.Controllers; namespace Tgstation.Server.Tests { @@ -380,6 +382,29 @@ static string GetMigrationTimestampString(Type type) => type Assert.AreEqual(latestMigrationSL, DatabaseContext.SLLatestMigration); } + [TestMethod] + public async Task CheckWebRootPathForTgsLogo() + { + var directory = Path.GetFullPath("../../../../../src/Tgstation.Server.Host/wwwroot"); + if (!Directory.Exists(directory)) + Assert.Inconclusive("Webpanel not built?"); + + var logo = new PlatformIdentifier().IsWindows + ? RootController.ProjectLogoSvgRouteWindows + : RootController.ProjectLogoSvgRouteLinux; + + var path = $"../../../../../src/Tgstation.Server.Host/wwwroot{logo}"; + Assert.IsTrue(File.Exists(path)); + + var content = await File.ReadAllBytesAsync(path); + var hash = String.Join(String.Empty, SHA1.HashData(content).Select(b => b.ToString("x2", CultureInfo.InvariantCulture))); + Assert.AreEqual( + new PlatformIdentifier().IsWindows + ? "c5e4709774c14a6f376dbb5100bd80a0114a2287" + : "9eba2fac24c5c7e0008721690d07c3df575a00d6", + hash); + } + static async Task> GetByondVersionPriorTo(IByondInstaller byondInstaller, Version version) { var minusOneMinor = new Version(version.Major, version.Minor - 1); From 22bd831c8c89d027eac699db8945e2ca017119fe Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 10 Nov 2023 23:23:19 -0500 Subject: [PATCH 161/717] Only create `tgstation-server` user + other permission fixes on first install. --- build/package/deb/debian/postinst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/build/package/deb/debian/postinst b/build/package/deb/debian/postinst index 9a1cb1b13c0..664ce89a97c 100755 --- a/build/package/deb/debian/postinst +++ b/build/package/deb/debian/postinst @@ -1,10 +1,12 @@ #!/bin/sh -e -adduser --system tgstation-server -mkdir -m 754 -p /var/log/tgstation-server -chown -R tgstation-server /etc/tgstation-server -chown -R tgstation-server /opt/tgstation-server -chown -R tgstation-server /var/log/tgstation-server +if [ -z "$2" ]; then + adduser --system tgstation-server + mkdir -m 754 -p /var/log/tgstation-server + chown -R tgstation-server /etc/tgstation-server + chown -R tgstation-server /opt/tgstation-server + chown -R tgstation-server /var/log/tgstation-server +fi #DEBHELPER# From 1527900571b25393a57c6dc28e81212cbf43f4c4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 10 Nov 2023 23:23:46 -0500 Subject: [PATCH 162/717] Fix .deb installation directory ownership --- build/package/deb/debian/postinst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/deb/debian/postinst b/build/package/deb/debian/postinst index 664ce89a97c..a40084e5eb6 100755 --- a/build/package/deb/debian/postinst +++ b/build/package/deb/debian/postinst @@ -4,7 +4,7 @@ if [ -z "$2" ]; then adduser --system tgstation-server mkdir -m 754 -p /var/log/tgstation-server chown -R tgstation-server /etc/tgstation-server - chown -R tgstation-server /opt/tgstation-server + chown -R tgstation-server /opt/tgstation-server/lib chown -R tgstation-server /var/log/tgstation-server fi From 80d5098cbb6c8c4243d15f7ff2e20132b6992f4b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 11 Nov 2023 14:36:24 -0500 Subject: [PATCH 163/717] Rename `ShaIsParent` to `CommittishIsParent` Update functionality to reflect this. --- .../Remote/GitHubRemoteDeploymentManager.cs | 2 +- .../Remote/GitLabRemoteDeploymentManager.cs | 2 +- .../Components/Engine/OpenDreamInstaller.cs | 2 +- .../Components/Repository/IRepository.cs | 8 +++--- .../Components/Repository/Repository.cs | 26 ++++++++++++++++--- .../Engine/TestOpenDreamInstaller.cs | 2 +- .../Tgstation.Server.Tests/TestRepository.cs | 4 +-- 7 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs index a31780bf214..751bb336461 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs @@ -198,7 +198,7 @@ async ValueTask CheckRemovePR(Task task) return; // We don't just assume, actually check the repo contains the merge commit. - if (await repository.ShaIsParent(pr.MergeCommitSha, cancellationToken)) + if (await repository.CommittishIsParent(pr.MergeCommitSha, cancellationToken)) { if (lastMerged == null || lastMerged.MergedAt < pr.MergedAt) lastMerged = pr; diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs index 3154b2ee03c..2686764cca0 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs @@ -83,7 +83,7 @@ async ValueTask CheckRemoveMR(Task task) return; // We don't just assume, actually check the repo contains the merge commit. - if (await repository.ShaIsParent(mergeRequest.MergeCommitSha, cancellationToken)) + if (await repository.CommittishIsParent(mergeRequest.MergeCommitSha, cancellationToken)) { if (lastMerged == null || lastMerged.ClosedAt < mergeRequest.ClosedAt) lastMerged = mergeRequest; diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index e279f0d0ccd..ceb95a810fe 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -152,7 +152,7 @@ await repo.CheckoutObject( progressSection2, cancellationToken); - if (!await repo.ShaIsParent("fab769776dada6b9bcad546094d78c604049e0e9", cancellationToken)) + if (!await repo.CommittishIsParent("fab769776dada6b9bcad546094d78c604049e0e9", cancellationToken)) throw new JobException(ErrorCode.OpenDreamTooOld); return new RepositoryEngineInstallationData(IOManager, repo, InstallationSourceSubDirectory); diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepository.cs b/src/Tgstation.Server.Host/Components/Repository/IRepository.cs index 33c4b9a97c0..0482eaaa902 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IRepository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IRepository.cs @@ -170,13 +170,13 @@ ValueTask Sychronize( ValueTask CopyTo(string path, CancellationToken cancellationToken); /// - /// Check if a given is a parent of the current . + /// Check if a given is a parent of the current . /// - /// The SHA to check. + /// The committish of the SHA to check. /// The for the operation. - /// A resulting in if is a parent of , otherwise. + /// A resulting in if is a parent of , otherwise. /// This function is NOT reentrant. - Task ShaIsParent(string sha, CancellationToken cancellationToken); + Task CommittishIsParent(string committish, CancellationToken cancellationToken); /// /// Get the tracked reference's current SHA. diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs index 5f3602675e2..cae1677f602 100644 --- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs @@ -791,16 +791,34 @@ public Task IsSha(string committish, CancellationToken cancellationToken) TaskScheduler.Current); /// - public Task ShaIsParent(string sha, CancellationToken cancellationToken) => Task.Factory.StartNew( + public Task CommittishIsParent(string committish, CancellationToken cancellationToken) => Task.Factory.StartNew( () => { - var targetCommit = libGitRepo.Lookup(sha); - if (targetCommit == null) + var targetObject = libGitRepo.Lookup(committish); + if (targetObject == null) { - logger.LogTrace("Commit {sha} not found in repository", sha); + logger.LogTrace("Committish {committish} not found in repository", committish); return false; } + if (targetObject is not Commit targetCommit) + { + if (targetObject is not TagAnnotation) + { + logger.LogTrace("Committish {committish} is a {type} and does not point to a commit!", committish, targetObject.GetType().Name); + return false; + } + + targetCommit = targetObject.Peel(); + if (targetCommit == null) + { + logger.LogError( + "TagAnnotation {committish} was found but the commit associated with it could not be found in repository!", + committish); + return false; + } + } + cancellationToken.ThrowIfCancellationRequested(); var startSha = Head; var mergeResult = libGitRepo.Merge( diff --git a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs index 6330ef1b104..6b8024ddac8 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs @@ -40,7 +40,7 @@ static async Task RepoDownloadTest(bool needsClone) var cloneAttempts = 0; var mockRepository = new Mock(); - mockRepository.Setup(x => x.ShaIsParent(It.IsNotNull(), It.IsAny())).ReturnsAsync(true); + mockRepository.Setup(x => x.CommittishIsParent(It.IsNotNull(), It.IsAny())).ReturnsAsync(true); var mockRepositoryManager = new Mock(); mockRepositoryManager.Setup(x => x.CloneRepository( generalConfig.OpenDreamGitUrl, diff --git a/tests/Tgstation.Server.Tests/TestRepository.cs b/tests/Tgstation.Server.Tests/TestRepository.cs index e03fbe984a7..8a16f0ddd91 100644 --- a/tests/Tgstation.Server.Tests/TestRepository.cs +++ b/tests/Tgstation.Server.Tests/TestRepository.cs @@ -42,10 +42,10 @@ public async Task TestRepoParentLookup() const string StartSha = "af4da8beb9f9b374b04a3cc4d65acca662e8cc1a"; await repo.CheckoutObject(StartSha, null, null, true, new JobProgressReporter(Mock.Of>(), null, (stage, progress) => { }), CancellationToken.None); - var result = await repo.ShaIsParent("2f8588a3ca0f6b027704a2a04381215619de3412", CancellationToken.None); + var result = await repo.CommittishIsParent("2f8588a3ca0f6b027704a2a04381215619de3412", CancellationToken.None); Assert.IsTrue(result); Assert.AreEqual(StartSha, repo.Head); - result = await repo.ShaIsParent("f636418bf47d238d33b0e4a34f0072b23a8aad0e", CancellationToken.None); + result = await repo.CommittishIsParent("f636418bf47d238d33b0e4a34f0072b23a8aad0e", CancellationToken.None); Assert.IsFalse(result); Assert.AreEqual(StartSha, repo.Head); } From de714c336994d859128de334811029ee7f681c49 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 11 Nov 2023 13:27:15 -0500 Subject: [PATCH 164/717] We now have the `tgs-min-compat` OD tag --- .github/workflows/ci-pipeline.yml | 2 +- .../Components/Engine/OpenDreamInstaller.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 18b9c28aad1..39bd74ee1a6 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -171,7 +171,7 @@ jobs: strategy: fail-fast: false matrix: - committish: [ 'master' ] + committish: [ 'master', 'tgs-min-compat' ] runs-on: ubuntu-latest steps: - name: Setup dotnet diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index ceb95a810fe..5175c7dc8a6 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -152,7 +152,7 @@ await repo.CheckoutObject( progressSection2, cancellationToken); - if (!await repo.CommittishIsParent("fab769776dada6b9bcad546094d78c604049e0e9", cancellationToken)) + if (!await repo.CommittishIsParent("tgs-min-compat", cancellationToken)) throw new JobException(ErrorCode.OpenDreamTooOld); return new RepositoryEngineInstallationData(IOManager, repo, InstallationSourceSubDirectory); From 7310359f0bed359e0cf0471254e4f176ebd40591 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 11 Nov 2023 14:08:38 -0500 Subject: [PATCH 165/717] OD uses UDP, so bind test to account for that --- .../Components/InstanceManager.cs | 2 +- .../Session/SessionControllerFactory.cs | 7 ++++--- .../Extensions/SocketExtensions.cs | 13 +++++++++---- .../Utils/PortAllocator.cs | 3 ++- .../Live/Instance/WatchdogTest.cs | 17 +++++++++++++++-- .../Live/TestLiveServer.cs | 1 - 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index 18dbd43fdbe..0959e9ca018 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -648,7 +648,7 @@ void CheckSystemCompatibility() // This runs before the real socket is opened, ensures we don't perform reattaches unless we're fairly certain the bind won't fail // If it does fail, DD will be killed. - SocketExtensions.BindTest(platformIdentifier, serverPortProvider.HttpApiPort, true); + SocketExtensions.BindTest(platformIdentifier, serverPortProvider.HttpApiPort, true, false); } /// diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 6c7b054367f..3670e146b94 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -130,9 +130,10 @@ sealed class SessionControllerFactory : ISessionControllerFactory /// Check if a given can be bound to. /// /// The port number to test. + /// The we're bind testing for. /// The for the operation. /// A representing the running operation. - async ValueTask PortBindTest(ushort port, CancellationToken cancellationToken) + async ValueTask PortBindTest(ushort port, EngineType engineType, CancellationToken cancellationToken) { logger.LogTrace("Bind test: {port}", port); try @@ -142,7 +143,7 @@ async ValueTask PortBindTest(ushort port, CancellationToken cancellationToken) for (var i = 0; i < MaxAttempts; ++i) try { - SocketExtensions.BindTest(platformIdentifier, port, false); + SocketExtensions.BindTest(platformIdentifier, port, false, engineType == EngineType.OpenDream); if (i > 0) logger.LogDebug("Clearing the socket took {iterations} attempts :/", i + 1); @@ -271,7 +272,7 @@ public async ValueTask LaunchNew( if (engineType == EngineType.Byond) await CheckPagerIsNotRunning(); - await PortBindTest(launchParameters.Port.Value, cancellationToken); + await PortBindTest(launchParameters.Port.Value, engineType, cancellationToken); string outputFilePath = null; var preserveLogFile = true; diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs index 3c5d076e723..6c1a695025e 100644 --- a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs @@ -17,7 +17,8 @@ static class SocketExtensions /// The to use. /// The port number to bind to. /// If IPV6 should be tested as well. - public static void BindTest(IPlatformIdentifier platformIdentifier, ushort port, bool includeIPv6) + /// If we're bind testing for UDP. If TCP will be checked. + public static void BindTest(IPlatformIdentifier platformIdentifier, ushort port, bool includeIPv6, bool udp) { ArgumentNullException.ThrowIfNull(platformIdentifier); ProcessExecutor.WithProcessLaunchExclusivity(() => @@ -26,12 +27,16 @@ public static void BindTest(IPlatformIdentifier platformIdentifier, ushort port, includeIPv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.Tcp); + udp + ? SocketType.Dgram + : SocketType.Stream, + udp + ? ProtocolType.Udp + : ProtocolType.Tcp); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); - if (platformIdentifier.IsWindows) + if (!udp && platformIdentifier.IsWindows) socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); if (includeIPv6) diff --git a/src/Tgstation.Server.Host/Utils/PortAllocator.cs b/src/Tgstation.Server.Host/Utils/PortAllocator.cs index cf53aabe11a..310cfbfe3da 100644 --- a/src/Tgstation.Server.Host/Utils/PortAllocator.cs +++ b/src/Tgstation.Server.Host/Utils/PortAllocator.cs @@ -101,7 +101,8 @@ public PortAllocator( try { - SocketExtensions.BindTest(platformIdentifier, port, false); + SocketExtensions.BindTest(platformIdentifier, port, false, true); + SocketExtensions.BindTest(platformIdentifier, port, false, false); } catch (Exception ex) { diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 473861045e0..31b64c65ba5 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -1,5 +1,6 @@ using Byond.TopicSender; +using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -19,6 +20,7 @@ using System.Net.Sockets; using System.Reflection; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.Arm; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -39,6 +41,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; +using static NuGet.Frameworks.FrameworkConstants; + namespace Tgstation.Server.Tests.Live.Instance { sealed class WatchdogTest : JobsRequiredTest @@ -544,10 +548,19 @@ async Task RunBasicTest(CancellationToken cancellationToken) JobResponse startJob; if (new PlatformIdentifier().IsWindows) // Can't get address reuse to trigger on linux for some reason - using (var blockSocket = new Socket(SocketType.Stream, ProtocolType.Tcp)) + using (var blockSocket = new Socket( + testVersion.Engine.Value == EngineType.OpenDream + ? SocketType.Dgram + : SocketType.Stream, + testVersion.Engine.Value == EngineType.OpenDream + ? ProtocolType.Udp + : ProtocolType.Tcp)) { blockSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true); blockSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); + if (testVersion.Engine.Value != EngineType.OpenDream) + blockSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true); + blockSocket.Bind(new IPEndPoint(IPAddress.Any, ddPort)); // Don't use StartDD here @@ -742,7 +755,7 @@ async Task StartDD(CancellationToken cancellationToken) { try { - SocketExtensions.BindTest(new PlatformIdentifier(), ddPort, false); + SocketExtensions.BindTest(new PlatformIdentifier(), ddPort, false, testVersion.Engine == EngineType.OpenDream); break; } catch diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index faf694db0e6..681f4ea902a 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -546,7 +546,6 @@ public async Task TestSwarmSynchronizationAndUpdates() { // cleanup existing directories new LiveTestingServer(null, false).Dispose(); - const string PrivateKey = "adlfj73ywifhks7iwrgfegjs"; var controllerAddress = new Uri("http://localhost:15011"); From 34872f22c0fc86cddd05239cdb790a67b30d24fe Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 12 Nov 2023 08:50:27 -0500 Subject: [PATCH 166/717] Give into Pomelo's nightly nuget feed --- NuGet.config | 7 +++++++ src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 NuGet.config diff --git a/NuGet.config b/NuGet.config new file mode 100644 index 00000000000..95d7e9642f6 --- /dev/null +++ b/NuGet.config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 0f0ab67d121..f635c053f5a 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -99,7 +99,7 @@ - + From be741edd3ab20d455c08a66e4e30c9df57f21eaa Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 12 Nov 2023 15:09:43 -0500 Subject: [PATCH 167/717] Most minor of code cleanups --- tests/Tgstation.Server.Host.Tests.Signals/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Host.Tests.Signals/Program.cs b/tests/Tgstation.Server.Host.Tests.Signals/Program.cs index 807fea235a1..92a733e59d2 100644 --- a/tests/Tgstation.Server.Host.Tests.Signals/Program.cs +++ b/tests/Tgstation.Server.Host.Tests.Signals/Program.cs @@ -21,7 +21,7 @@ static async Task Main() var tcs = new TaskCompletionSource(); mockServerControl .Setup(x => x.GracefulShutdown(It.IsAny())) - .Callback(() => tcs.SetResult()) + .Callback(tcs.SetResult) .Returns(ValueTask.CompletedTask); var mockAsyncDelayer = new Mock(); From baa893ec1d3345e627ced7a00ce6d3c8e8f858a5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 13 Nov 2023 19:14:50 -0500 Subject: [PATCH 168/717] Test OpenDream with TGS deployment --- .github/workflows/ci-pipeline.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 06285af65a5..55bd1bfb329 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -39,6 +39,7 @@ on: env: TGS_DOTNET_VERSION: 8 + OD_DOTNET_VERSION: 7 TGS_DOTNET_QUALITY: preview TGS_TEST_GITHUB_TOKEN: ${{ secrets.LIVE_TESTS_TOKEN }} TGS_RELEASE_NOTES_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} @@ -198,15 +199,15 @@ jobs: git checkout ${{ matrix.committish }} git submodule update --init --recursive - - name: Build OpenDream + - name: Create TGS Deployment run: | cd $HOME/OpenDream - dotnet build -c Release + dotnet run -c Release --project OpenDreamPackageTool -- --tgs -o tgs_deploy - name: Build DMAPI run: | cd tests/DMAPI/BasicOperation - $HOME/OpenDream/bin/DMCompiler/DMCompiler --verbose --notices-enabled basic_operation_test.dme + $HOME/OpenDream/tgs_deploy/bin/compiler/DMCompiler --verbose --notices-enabled basic_operation_test.dme pages-build: name: Build gh-pages @@ -427,7 +428,8 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-version: + '${{ env.TGS_DOTNET_VERSION }}.0.x' dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Set TGS_TEST_DUMP_API_SPEC From 0b817718edc727183ce783bb67df6c550926ad45 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 13 Nov 2023 19:29:52 -0500 Subject: [PATCH 169/717] Terminate OD builds if cancelled --- .../Components/Engine/OpenDreamInstaller.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 5175c7dc8a6..7421bd58b8b 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -232,7 +232,10 @@ await HandleExtremelyLongPathOperation( null, true, true); - buildExitCode = await buildProcess.Lifetime; + + using (cancellationToken.Register(() => buildProcess.Terminate())) + buildExitCode = await buildProcess.Lifetime; + Logger.LogDebug( "OpenDream build exited with code {exitCode}:{newLine}{output}", buildExitCode, From 25c9cc49d5a13d8a4026d464aa98abcfb411dc42 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 13 Nov 2023 19:31:26 -0500 Subject: [PATCH 170/717] Log spam for OD build hang --- .../Components/Engine/OpenDreamInstaller.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 7421bd58b8b..934726e8653 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -236,6 +236,8 @@ await HandleExtremelyLongPathOperation( using (cancellationToken.Register(() => buildProcess.Terminate())) buildExitCode = await buildProcess.Lifetime; + Logger.LogTrace("OD build complete, waiting for output..."); + Logger.LogDebug( "OpenDream build exited with code {exitCode}:{newLine}{output}", buildExitCode, From e2e0114770fb9fa97ab6eef3e7068d6aab0cd512 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 14 Nov 2023 13:53:57 -0500 Subject: [PATCH 171/717] Update .NET 8.0 release - Update Microsoft packages. - Update EF Core tooling. - Update Docker base images. - Update build scripts. - Update actions. --- .github/workflows/ci-pipeline.yml | 2 +- .github/workflows/code-scanning.yml | 2 +- build/Dockerfile | 4 ++-- build/Version.props | 2 +- build/package/deb/build_package.sh | 4 ++-- build/package/deb/debian/control | 4 ++-- .../Tgstation.Server.Client.csproj | 4 ++-- .../Tgstation.Server.Host.Console.csproj | 2 +- .../Tgstation.Server.Host.Service.csproj | 8 ++++---- .../Tgstation.Server.Host.Watchdog.csproj | 2 +- .../.config/dotnet-tools.json | 2 +- .../Tgstation.Server.Host.csproj | 20 +++++++++---------- .../Tgstation.Server.Client.Tests.csproj | 2 +- .../Tgstation.Server.Host.Tests.csproj | 2 +- .../Tgstation.Server.Tests.csproj | 2 +- .../Tgstation.Server.Migrator.csproj | 2 +- 16 files changed, 32 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 290460f8ad9..522f37e6f2c 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -39,7 +39,7 @@ on: env: TGS_DOTNET_VERSION: 8 - TGS_DOTNET_QUALITY: preview + TGS_DOTNET_QUALITY: ga TGS_TEST_GITHUB_TOKEN: ${{ secrets.LIVE_TESTS_TOKEN }} TGS_RELEASE_NOTES_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} WINGET_PUSH_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml index 307500697d2..9442ce55308 100644 --- a/.github/workflows/code-scanning.yml +++ b/.github/workflows/code-scanning.yml @@ -16,7 +16,7 @@ on: env: TGS_DOTNET_VERSION: 8 - TGS_DOTNET_QUALITY: preview + TGS_DOTNET_QUALITY: ga concurrency: group: "code-scanning-${{ github.head_ref || github.run_id }}-${{ github.event_name }}" diff --git a/build/Dockerfile b/build/Dockerfile index 9304b65d4b7..383df77bfb0 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0-preview-bookworm-slim AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim AS build # install node and npm # replace shell with bash so we can source files @@ -49,7 +49,7 @@ RUN dotnet publish -c Release -o /app/lib/Default \ && build/RemoveUnsupportedRuntimes.sh /app/lib/Default \ && mv /app/lib/Default/appsettings* /app -FROM mcr.microsoft.com/dotnet/aspnet:8.0-preview-bookworm-slim +FROM mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim #needed for byond RUN apt-get update \ diff --git a/build/Version.props b/build/Version.props index c08eccf5ff0..a033a4e181b 100644 --- a/build/Version.props +++ b/build/Version.props @@ -17,7 +17,7 @@ netstandard2.0 8 - https://download.visualstudio.microsoft.com/download/pr/f0a627b7-bd46-4ed2-978d-00a445174074/182420f488062f1983fc392b2fb66967/dotnet-hosting-8.0.0-rc.2.23480.2-win.exe + https://download.visualstudio.microsoft.com/download/pr/2a7ae819-fbc4-4611-a1ba-f3b072d4ea25/32f3b931550f7b315d9827d564202eeb/dotnet-hosting-8.0.0-win.exe 10.11.6 1.22.19 diff --git a/build/package/deb/build_package.sh b/build/package/deb/build_package.sh index 79f2e57244e..8f55150d326 100755 --- a/build/package/deb/build_package.sh +++ b/build/package/deb/build_package.sh @@ -19,8 +19,8 @@ apt-get install -y \ ca-certificates \ curl \ gnupg \ - xmlstarlet -# dotnet-sdk-8.0 # Disabled while in preview + xmlstarlet \ + dotnet-sdk-8.0 # https://github.com/nodesource/distributions mkdir -p /etc/apt/keyrings diff --git a/build/package/deb/debian/control b/build/package/deb/debian/control index a63d1d0fab5..f0a7ecbbe3f 100644 --- a/build/package/deb/debian/control +++ b/build/package/deb/debian/control @@ -6,7 +6,7 @@ Rules-Requires-Root: no Build-Depends: debhelper-compat (= 13), nodejs, -#dotnet-sdk-8.0, Disabled while in preview + dotnet-sdk-8.0, Standards-Version: 4.6.2 Homepage: https://tgstation.github.io/tgstation-server Vcs-Browser: https://github.com/tgstation/tgstation-server @@ -16,7 +16,7 @@ Package: tgstation-server Architecture: any Depends: ${misc:Depends}, -#aspnetcore-runtime-8.0, Disabled while in preview + aspnetcore-runtime-8.0, libc6-i386, libstdc++6:i386 [amd64], libstdc++6 [i386], diff --git a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj index 3b62a38903f..21eff94c4bb 100644 --- a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj +++ b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj @@ -12,9 +12,9 @@ - + - + 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 89392d1fb6d..92902912bb3 100644 --- a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj +++ b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj @@ -11,7 +11,7 @@ - + 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 a7c6d3c406a..aa98536f387 100644 --- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj +++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj @@ -19,15 +19,15 @@ - + - + - + - + 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 5428b3b8488..ae3b89cdb27 100644 --- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj +++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Tgstation.Server.Host/.config/dotnet-tools.json b/src/Tgstation.Server.Host/.config/dotnet-tools.json index 7bf21904659..c03564f9704 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.0-rc.2.23479.6", + "version": "8.0.0", "commands": [ "dotnet-ef" ] diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index d42f52b825d..33a2f815b36 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -75,21 +75,21 @@ - + - + - + - + - + runtime; build; native; contentfiles; analyzers; buildtransitive - + - + @@ -117,13 +117,13 @@ - + - + - + 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 cfc5f1ae7e8..c2c09fe7b87 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 f0f88a74b57..331d95e564d 100644 --- a/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj +++ b/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj b/tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj index dc0fbd8f54d..bbcbbc86edd 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/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj b/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj index c445f31201c..2511e50c18c 100644 --- a/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj +++ b/tools/Tgstation.Server.Migrator/Tgstation.Server.Migrator.csproj @@ -14,7 +14,7 @@ - + From 1b661d8e3fdfb307bd9f9ea832f23732c7d81bed Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 14 Nov 2023 16:58:35 -0500 Subject: [PATCH 172/717] Always install .NET from Microsoft Ubuntu repo Can't be assed to wait for releases --- build/package/deb/build_package.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/build/package/deb/build_package.sh b/build/package/deb/build_package.sh index 8f55150d326..0732f96486e 100755 --- a/build/package/deb/build_package.sh +++ b/build/package/deb/build_package.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Run from git root +# Run from git root, certified for ubuntu only since that's what gha uses SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) @@ -19,8 +19,12 @@ apt-get install -y \ ca-certificates \ curl \ gnupg \ - xmlstarlet \ - dotnet-sdk-8.0 + xmlstarlet + +declare repo_version=$(if command -v lsb_release &> /dev/null; then lsb_release -r -s; else grep -oP '(?<=^VERSION_ID=).+' /etc/os-release | tr -d '"'; fi) +curl -L https://packages.microsoft.com/config/ubuntu/$repo_version/packages-microsoft-prod.deb -o packages-microsoft-prod.deb +dpkg -i ./packages-microsoft-prod.deb +rm packages-microsoft-prod.deb # https://github.com/nodesource/distributions mkdir -p /etc/apt/keyrings @@ -28,7 +32,7 @@ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dea export NODE_MAJOR=20 echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list apt-get update -apt-get install nodejs -y +apt-get install nodejs dotnet-sdk-8.0 -y CURRENT_COMMIT=$(git rev-parse HEAD) From d2a861415ae2eec487977b250defdd795b1a3425 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 14 Nov 2023 17:26:47 -0500 Subject: [PATCH 173/717] Update to latest EFCore extensions version --- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 33a2f815b36..ece85029e7c 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -125,7 +125,7 @@ - + From 75db9af33eaa676ec4712a65f185c78623ecf604 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 14 Nov 2023 19:51:08 -0500 Subject: [PATCH 174/717] Move `EngineVersion` to core models namespace --- .../Models/{Internal => }/EngineVersion.cs | 2 +- .../Models/Request/EngineVersionDeleteRequest.cs | 6 ++---- .../Models/Request/EngineVersionRequest.cs | 6 ++---- .../Models/Response/EngineInstallResponse.cs | 2 +- .../Models/Response/EngineResponse.cs | 8 +++----- src/Tgstation.Server.Client/Components/IEngineClient.cs | 4 ++-- src/Tgstation.Server.Host/Components/Chat/ChatManager.cs | 5 +++-- .../Components/Chat/Commands/EngineCommand.cs | 1 - src/Tgstation.Server.Host/Components/Chat/IChatManager.cs | 4 ++-- .../Components/Chat/Providers/IProvider.cs | 4 ++-- .../Components/Chat/Providers/IrcProvider.cs | 1 - .../Components/Chat/Providers/Provider.cs | 7 +++---- .../Components/Deployment/DmbFactory.cs | 3 ++- .../Components/Deployment/DmbProvider.cs | 1 + .../Components/Deployment/IDmbProvider.cs | 4 ++-- .../Components/Deployment/SwappableDmbProvider.cs | 2 +- .../Components/Deployment/TemporaryDmbProvider.cs | 2 +- .../Components/Engine/ByondInstallerBase.cs | 1 - .../Components/Engine/DelegatingEngineInstaller.cs | 1 - .../Components/Engine/EngineExecutableLock.cs | 1 + .../Components/Engine/EngineInstallationBase.cs | 1 + .../Components/Engine/EngineInstallerBase.cs | 1 - .../Components/Engine/EngineManager.cs | 1 - .../Components/Engine/IEngineInstallation.cs | 1 + .../Components/Engine/IEngineInstaller.cs | 2 +- .../Components/Engine/IEngineManager.cs | 1 - .../Components/Engine/OpenDreamInstaller.cs | 1 - .../Components/Engine/PosixByondInstaller.cs | 2 +- .../Components/Engine/WindowsByondInstaller.cs | 1 - .../Components/Engine/WindowsOpenDreamInstaller.cs | 1 - .../Components/Session/ISessionController.cs | 4 ++-- src/Tgstation.Server.Host/Models/CompileJob.cs | 2 +- tests/Tgstation.Server.Tests/CachingFileDownloader.cs | 1 + tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs | 5 ++--- tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs | 1 - .../Tgstation.Server.Tests/Live/Instance/InstanceTest.cs | 1 - .../Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 1 - tests/Tgstation.Server.Tests/TestVersions.cs | 1 - 38 files changed, 39 insertions(+), 54 deletions(-) rename src/Tgstation.Server.Api/Models/{Internal => }/EngineVersion.cs (99%) diff --git a/src/Tgstation.Server.Api/Models/Internal/EngineVersion.cs b/src/Tgstation.Server.Api/Models/EngineVersion.cs similarity index 99% rename from src/Tgstation.Server.Api/Models/Internal/EngineVersion.cs rename to src/Tgstation.Server.Api/Models/EngineVersion.cs index 2f3279e93bb..793cf147f64 100644 --- a/src/Tgstation.Server.Api/Models/Internal/EngineVersion.cs +++ b/src/Tgstation.Server.Api/Models/EngineVersion.cs @@ -5,7 +5,7 @@ using Tgstation.Server.Common.Extensions; -namespace Tgstation.Server.Api.Models.Internal +namespace Tgstation.Server.Api.Models { /// /// Information about an engine installation. diff --git a/src/Tgstation.Server.Api/Models/Request/EngineVersionDeleteRequest.cs b/src/Tgstation.Server.Api/Models/Request/EngineVersionDeleteRequest.cs index d9526eef999..6002483ca1e 100644 --- a/src/Tgstation.Server.Api/Models/Request/EngineVersionDeleteRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/EngineVersionDeleteRequest.cs @@ -1,6 +1,4 @@ -using Tgstation.Server.Api.Models.Internal; - -namespace Tgstation.Server.Api.Models.Request +namespace Tgstation.Server.Api.Models.Request { /// /// A request to delete a specific . @@ -8,7 +6,7 @@ namespace Tgstation.Server.Api.Models.Request public class EngineVersionDeleteRequest { /// - /// The to delete. + /// The to delete. /// public EngineVersion? EngineVersion { get; set; } } diff --git a/src/Tgstation.Server.Api/Models/Request/EngineVersionRequest.cs b/src/Tgstation.Server.Api/Models/Request/EngineVersionRequest.cs index a1a045a73a9..4a9a7dc7993 100644 --- a/src/Tgstation.Server.Api/Models/Request/EngineVersionRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/EngineVersionRequest.cs @@ -1,6 +1,4 @@ -using Tgstation.Server.Api.Models.Internal; - -namespace Tgstation.Server.Api.Models.Request +namespace Tgstation.Server.Api.Models.Request { /// /// A request to switch to a given . @@ -8,7 +6,7 @@ namespace Tgstation.Server.Api.Models.Request public sealed class EngineVersionRequest { /// - /// The to switch to. + /// The to switch to. /// public EngineVersion? EngineVersion { get; set; } diff --git a/src/Tgstation.Server.Api/Models/Response/EngineInstallResponse.cs b/src/Tgstation.Server.Api/Models/Response/EngineInstallResponse.cs index 7972f5d6217..95d52002395 100644 --- a/src/Tgstation.Server.Api/Models/Response/EngineInstallResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/EngineInstallResponse.cs @@ -6,7 +6,7 @@ public sealed class EngineInstallResponse : FileTicketResponse { /// - /// The being used to install a new . + /// The being used to install a new . /// [ResponseOptions] public JobResponse? InstallJob { get; set; } diff --git a/src/Tgstation.Server.Api/Models/Response/EngineResponse.cs b/src/Tgstation.Server.Api/Models/Response/EngineResponse.cs index b9de3753fa9..f9768f0a7e4 100644 --- a/src/Tgstation.Server.Api/Models/Response/EngineResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/EngineResponse.cs @@ -1,14 +1,12 @@ -using Tgstation.Server.Api.Models.Internal; - -namespace Tgstation.Server.Api.Models.Response +namespace Tgstation.Server.Api.Models.Response { /// - /// Represents an installed . + /// Represents an installed . /// public sealed class EngineResponse { /// - /// The represented . If that indicates none were found. + /// The represented . If that indicates none were found. /// public EngineVersion? EngineVersion { get; set; } } diff --git a/src/Tgstation.Server.Client/Components/IEngineClient.cs b/src/Tgstation.Server.Client/Components/IEngineClient.cs index d097b72f3a4..046f81e0bce 100644 --- a/src/Tgstation.Server.Client/Components/IEngineClient.cs +++ b/src/Tgstation.Server.Client/Components/IEngineClient.cs @@ -14,7 +14,7 @@ namespace Tgstation.Server.Client.Components public interface IEngineClient { /// - /// Get the active . + /// Get the active . /// /// The for the operation. /// A resulting in the . @@ -40,7 +40,7 @@ public interface IEngineClient /// /// Starts a job to delete a specific engine version. /// - /// The specifying the to delete. + /// The specifying the to delete. /// The for the operation. /// A resulting in the for the delete job. ValueTask DeleteVersion(EngineVersionDeleteRequest deleteRequest, CancellationToken cancellationToken); diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index d002d606241..47add7b2882 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -11,6 +11,7 @@ using Serilog.Context; +using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components.Chat.Commands; @@ -62,7 +63,7 @@ sealed class ChatManager : IChatManager, IRestartHandler readonly IDictionary builtinCommands; /// - /// Map of s in use, keyed by . + /// Map of s in use, keyed by . /// readonly IDictionary providers; @@ -586,7 +587,7 @@ public ValueTask HandleRestart(Version updateVersion, bool handlerMayDelayShutdo /// /// Remove a from optionally removing the provider itself from and updating the as well. /// - /// The of the to delete. + /// The of the to delete. /// If the provider should be removed from and should be update. /// The for the operation. /// A resulting in the being removed if it exists, otherwise. diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs index d29e45f9bd6..e2580cbf0bc 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Watchdog; diff --git a/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs index 41ca31f5c54..ae4aefb8fb3 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs @@ -61,7 +61,7 @@ public interface IChatManager : IComponentService, IAsyncDisposable /// Send the message for a deployment to configured deployment channels. /// /// The of the deployment. - /// The of the deployment. + /// The of the deployment. /// The optional the deployment is expected to be completed at. /// The repository GitHub owner, if any. /// The repository GitHub name, if any. @@ -69,7 +69,7 @@ public interface IChatManager : IComponentService, IAsyncDisposable /// A to call to update the message at the deployment's conclusion. Parameters: Error message if any, DreamMaker output if any. Returns an to call to mark the deployment as active/inactive. Parameter: If the deployment is being activated or inactivated. Func> QueueDeploymentMessage( Models.RevisionInformation revisionInformation, - EngineVersion engineVersion, + Api.Models.EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs index 109ec8a74c3..22028aefc77 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs @@ -84,7 +84,7 @@ interface IProvider : IAsyncDisposable /// Send the message for a deployment. /// /// The of the deployment. - /// The of the deployment. + /// The of the deployment. /// The optional the deployment is expected to be completed at. /// The repository GitHub owner, if any. /// The repository GitHub name, if any. @@ -94,7 +94,7 @@ interface IProvider : IAsyncDisposable /// A resulting in a to call to update the message at the deployment's conclusion. Parameters: Error message if any, DreamMaker output if any. Returns another callback which should be called to mark the deployment as active. ValueTask>>> SendUpdateMessage( Models.RevisionInformation revisionInformation, - EngineVersion engineVersion, + Api.Models.EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index 2e61723c943..8bca821cf1b 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -12,7 +12,6 @@ using Newtonsoft.Json; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs index 8279c14d97b..7da3b299308 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.Logging; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Rights; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Jobs; @@ -196,8 +195,8 @@ public Task SetReconnectInterval(uint reconnectInterval, bool connectNow) /// public abstract ValueTask>>> SendUpdateMessage( - Models.RevisionInformation revisionInformation, - EngineVersion engineVersion, + RevisionInformation revisionInformation, + Api.Models.EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, @@ -287,7 +286,7 @@ async Task ReconnectionLoop(uint reconnectInterval, bool connectNow, Cancellatio connectNow = false; if (!Connected) { - var job = Models.Job.Create(Api.Models.JobCode.ReconnectChatBot, null, ChatBot.Instance, ChatBotRights.WriteEnabled); + var job = Job.Create(Api.Models.JobCode.ReconnectChatBot, null, ChatBot.Instance, ChatBotRights.WriteEnabled); job.Description += $": {ChatBot.Name}"; await jobManager.RegisterOperation( diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs index 13db5c999de..de36092c6b6 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs @@ -8,6 +8,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; +using Tgstation.Server.Api.Models; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components.Deployment.Remote; using Tgstation.Server.Host.Components.Events; @@ -250,7 +251,7 @@ await databaseContextFactory.UseContext( .ThenInclude(x => x.MergedBy) .FirstAsync(cancellationToken)); // can't wait to see that query - if (!Api.Models.Internal.EngineVersion.TryParse(compileJob.EngineVersion, out var engineVersion)) + if (!EngineVersion.TryParse(compileJob.EngineVersion, out var engineVersion)) { logger.LogWarning("Error loading compile job, bad engine version: {0}", compileJob.EngineVersion); return null; // omae wa mou shinderu diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs index e7b8b00eabe..37c44d9fab9 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; +using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; diff --git a/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs index 2791b940651..820796c3186 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs @@ -1,6 +1,6 @@ using System; -using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Api.Models; namespace Tgstation.Server.Host.Components.Deployment { @@ -25,7 +25,7 @@ public interface IDmbProvider : IAsyncDisposable Models.CompileJob CompileJob { get; } /// - /// The used to build the .dmb. + /// The used to build the .dmb. /// EngineVersion EngineVersion { get; } diff --git a/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs index 3f784d3331e..75c5a1b6bb1 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs @@ -2,7 +2,7 @@ using System.Threading; using System.Threading.Tasks; -using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Api.Models; using Tgstation.Server.Host.IO; namespace Tgstation.Server.Host.Components.Deployment diff --git a/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs index 47aadd150fb..4d528d7ba1e 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; -using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Api.Models; namespace Tgstation.Server.Host.Components.Deployment { diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index c584d42331f..217c49afdf9 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.Logging; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; diff --git a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs index ec8e7267c38..4a9c29cd7a2 100644 --- a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Jobs; diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs index 77c40caed9b..70614f13e17 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Utils; diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs index d8cc5f64ea3..fb607d36011 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using System.Web; +using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs index 9f1be75dd25..2b3c986d29d 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.Logging; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index d6425be223e..36365332dd3 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -10,7 +10,6 @@ using Microsoft.Extensions.Logging; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.IO; diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs index 1fc6c4ad7b5..af111b9a158 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs index bd59169206e..3bcd576e8dd 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs @@ -1,7 +1,7 @@ using System.Threading; using System.Threading.Tasks; -using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Jobs; namespace Tgstation.Server.Host.Components.Engine diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs index f4be62af6c6..bc272b1038a 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Jobs; namespace Tgstation.Server.Host.Components.Engine diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 934726e8653..30b7ce67132 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.Options; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Common; using Tgstation.Server.Host.Components.Repository; diff --git a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs index c4906308b5a..cddace53c8c 100644 --- a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs @@ -6,7 +6,7 @@ using Microsoft.Extensions.Logging; -using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Api.Models; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.IO; diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 9ce8e3cd4df..2af9b96a35f 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -8,7 +8,6 @@ using Microsoft.Extensions.Options; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index 36ae2c627ff..4f42884c7f3 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -6,7 +6,6 @@ using Microsoft.Extensions.Options; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Configuration; diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs index 89387811d65..89ba16b1929 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs @@ -2,7 +2,7 @@ using System.Threading; using System.Threading.Tasks; -using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Components.Interop.Topic; using Tgstation.Server.Host.System; @@ -40,7 +40,7 @@ interface ISessionController : IProcessBase, IRenameNotifyee, IAsyncDisposable Models.CompileJob CompileJob { get; } /// - /// Gets the associated with the . + /// Gets the associated with the . /// EngineVersion EngineVersion { get; } diff --git a/src/Tgstation.Server.Host/Models/CompileJob.cs b/src/Tgstation.Server.Host/Models/CompileJob.cs index 372e6504840..8ff0ab466d1 100644 --- a/src/Tgstation.Server.Host/Models/CompileJob.cs +++ b/src/Tgstation.Server.Host/Models/CompileJob.cs @@ -90,7 +90,7 @@ public override Version DMApiVersion Job = Job.ToApi(), Output = Output, RevisionInformation = RevisionInformation.ToApi(), - EngineVersion = Api.Models.Internal.EngineVersion.TryParse(EngineVersion, out var version) + EngineVersion = Api.Models.EngineVersion.TryParse(EngineVersion, out var version) ? version : throw new InvalidOperationException($"Failed to parse engine version: {EngineVersion}"), MinimumSecurityLevel = MinimumSecurityLevel, diff --git a/tests/Tgstation.Server.Tests/CachingFileDownloader.cs b/tests/Tgstation.Server.Tests/CachingFileDownloader.cs index 680307cd234..bd7d01bbbdb 100644 --- a/tests/Tgstation.Server.Tests/CachingFileDownloader.cs +++ b/tests/Tgstation.Server.Tests/CachingFileDownloader.cs @@ -9,6 +9,7 @@ using Moq; +using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Extensions; diff --git a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs index 411cfbc45cf..2edb4686eda 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs @@ -12,7 +12,6 @@ using Newtonsoft.Json; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Chat.Commands; using Tgstation.Server.Host.Components.Chat.Providers; @@ -103,8 +102,8 @@ public override ValueTask SendMessage(Message replyTo, MessageContent message, u } public override ValueTask>>> SendUpdateMessage( - Host.Models.RevisionInformation revisionInformation, - EngineVersion engineVersion, + RevisionInformation revisionInformation, + Api.Models.EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, diff --git a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs index d03ad60dba0..b90d054ef81 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs @@ -13,7 +13,6 @@ using Moq; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client; diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 50a2d9f116e..21a54ebce8e 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -13,7 +13,6 @@ using Moq; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client; diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 8a4e6de727c..5e3a7f8eb0b 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -26,7 +26,6 @@ using System.Threading.Tasks; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client; diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 80382f2fc26..eb0acb0b76e 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -30,7 +30,6 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models; using Tgstation.Server.Tests.Live; From d0fcfa06b624ec7af4b1bbf432150afb2230bf25 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 14 Nov 2023 19:51:15 -0500 Subject: [PATCH 175/717] Seal `EngineVersion` --- src/Tgstation.Server.Api/Models/EngineVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Api/Models/EngineVersion.cs b/src/Tgstation.Server.Api/Models/EngineVersion.cs index 793cf147f64..d4681faa60d 100644 --- a/src/Tgstation.Server.Api/Models/EngineVersion.cs +++ b/src/Tgstation.Server.Api/Models/EngineVersion.cs @@ -10,7 +10,7 @@ namespace Tgstation.Server.Api.Models /// /// Information about an engine installation. /// - public class EngineVersion : IEquatable + public sealed class EngineVersion : IEquatable { /// /// The . From b7b3f0db3f3ff97c3375b38adb33a68d09c9702e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 14 Nov 2023 19:56:03 -0500 Subject: [PATCH 176/717] Use OD's specific dotnet version where appropriate --- .github/workflows/ci-pipeline.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 42dbae2c061..9520412eb75 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -178,7 +178,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-version: '${{ env.OD_DOTNET_VERSION }}.0.x' dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout (Branch) @@ -428,8 +428,9 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v3 with: - dotnet-version: + dotnet-version: | '${{ env.TGS_DOTNET_VERSION }}.0.x' + '${{ env.OD_DOTNET_VERSION }}.0.x' dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Set TGS_TEST_DUMP_API_SPEC @@ -650,7 +651,9 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v3 with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-version: | + '${{ env.TGS_DOTNET_VERSION }}.0.x' + '${{ env.OD_DOTNET_VERSION }}.0.x' dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Set Sqlite Connection Info From 51e64951afe0904664293e2953dab69b70bf5a6f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 14 Nov 2023 22:52:38 -0500 Subject: [PATCH 177/717] Prevent the `RootController` from being included in the API --- src/Tgstation.Server.Host/Controllers/RootController.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tgstation.Server.Host/Controllers/RootController.cs b/src/Tgstation.Server.Host/Controllers/RootController.cs index fd1bf36b112..850785d6125 100644 --- a/src/Tgstation.Server.Host/Controllers/RootController.cs +++ b/src/Tgstation.Server.Host/Controllers/RootController.cs @@ -15,6 +15,7 @@ namespace Tgstation.Server.Host.Controllers /// The root path . /// [Route("/")] + [ApiExplorerSettings(IgnoreApi = true)] public sealed class RootController : Controller { /// From f286b0f46d43ff35cacb6040535107df7cb2b079 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 14 Nov 2023 23:26:52 -0500 Subject: [PATCH 178/717] Fix logic error in `EngineCommand` --- .../Components/Chat/Commands/EngineCommand.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs index e2580cbf0bc..9e92f3f02f1 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs @@ -75,6 +75,7 @@ public ValueTask Invoke(string arguments, ChatUser user, Cancell if (engineVersion == null) text = "None!"; else + { text = engineVersion.Engine.Value switch { EngineType.OpenDream => $"OpenDream: {engineVersion.SourceSHA}", @@ -82,8 +83,9 @@ public ValueTask Invoke(string arguments, ChatUser user, Cancell _ => throw new InvalidOperationException($"Invalid EngineType: {engineVersion.Engine.Value}"), }; - if (engineVersion.CustomIteration.HasValue) - text += $" (Custom Upload #{engineVersion.CustomIteration.Value})"; + if (engineVersion.CustomIteration.HasValue) + text += $" (Custom Upload #{engineVersion.CustomIteration.Value})"; + } return ValueTask.FromResult( new MessageContent From f5ebfaee7adbd32ee27cdd39fbf21245e7040e49 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 15 Nov 2023 08:20:09 -0500 Subject: [PATCH 179/717] Update Remora.Discord and Serilog.Extensions.Logging - New .net8 versions --- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index ece85029e7c..8b8ad755b25 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -101,9 +101,9 @@ - + - + From f87f36f03c9dab6cab2dbaaa8845df6408697456 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 15 Nov 2023 08:50:47 -0500 Subject: [PATCH 180/717] Correct .yml formatting --- .github/workflows/ci-pipeline.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index d26f4da0de1..11a821405e8 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -429,8 +429,8 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: | - '${{ env.TGS_DOTNET_VERSION }}.0.x' - '${{ env.OD_DOTNET_VERSION }}.0.x' + ${{ env.TGS_DOTNET_VERSION }}.0.x + ${{ env.OD_DOTNET_VERSION }}.0.x dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Set TGS_TEST_DUMP_API_SPEC @@ -652,8 +652,8 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: | - '${{ env.TGS_DOTNET_VERSION }}.0.x' - '${{ env.OD_DOTNET_VERSION }}.0.x' + ${{ env.TGS_DOTNET_VERSION }}.0.x + ${{ env.OD_DOTNET_VERSION }}.0.x dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Set Sqlite Connection Info From f405edd6446a40492761953fb45fe01e76f131af Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 15 Nov 2023 22:31:51 -0500 Subject: [PATCH 181/717] Hack to see if we can get any output out of this hung process --- .../Components/Engine/OpenDreamInstaller.cs | 54 ++++++++++++------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 30b7ce67132..2073ab4838e 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -224,24 +224,42 @@ await HandleExtremelyLongPathOperation( async shortenedPath => { var shortenedDeployPath = IOManager.ConcatPath(shortenedPath, DeployDir); - await using var buildProcess = ProcessExecutor.LaunchProcess( - dotnetPath, - shortenedPath, - $"run -c Release --project OpenDreamPackageTool -- --tgs -o {shortenedDeployPath}", - null, - true, - true); - - using (cancellationToken.Register(() => buildProcess.Terminate())) - buildExitCode = await buildProcess.Lifetime; - - Logger.LogTrace("OD build complete, waiting for output..."); - - Logger.LogDebug( - "OpenDream build exited with code {exitCode}:{newLine}{output}", - buildExitCode, - Environment.NewLine, - await buildProcess.GetCombinedOutput(cancellationToken)); + Task outputTask = null; + try + { + await using (var buildProcess = ProcessExecutor.LaunchProcess( + dotnetPath, + shortenedPath, + $"run -c Release --project OpenDreamPackageTool -- --tgs -o {shortenedDeployPath}", + null, + true, + true)) + { + using (cancellationToken.Register(() => buildProcess.Terminate())) + buildExitCode = await buildProcess.Lifetime; + + Logger.LogTrace("OD build complete, waiting for output..."); + + outputTask = buildProcess + .GetCombinedOutput(CancellationToken.None); // DCT: Special tactics because of a (dotnet? https://github.com/dotnet/runtime/issues/28583) bug + + await outputTask.WaitAsync(cancellationToken); + } + } + finally + { + if (outputTask != null) + { + if (!outputTask.IsCompleted) + await Task.Yield(); + if (outputTask.IsCompleted) + Logger.LogDebug( + "OpenDream build exited with code {exitCode}:{newLine}{output}", + buildExitCode, + Environment.NewLine, + await outputTask); + } + } }, sourcePath, cancellationToken); From 4537845e0bae19a92f88120dcde51c699f370f4c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 16 Nov 2023 18:17:07 -0500 Subject: [PATCH 182/717] Make this workaround generic --- .../Components/Engine/OpenDreamInstaller.cs | 53 ++++++------------- src/Tgstation.Server.Host/System/IProcess.cs | 5 +- src/Tgstation.Server.Host/System/Process.cs | 34 +++++++++++- .../System/ProcessExecutor.cs | 11 ++++ .../System/TestPosixSignalHandler.cs | 1 + .../Live/Instance/WatchdogTest.cs | 2 + .../Live/TestLiveServer.cs | 2 + .../TestSystemInteraction.cs | 3 ++ tests/Tgstation.Server.Tests/TestVersions.cs | 2 + 9 files changed, 73 insertions(+), 40 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 2073ab4838e..da7a9fae080 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -224,42 +224,23 @@ await HandleExtremelyLongPathOperation( async shortenedPath => { var shortenedDeployPath = IOManager.ConcatPath(shortenedPath, DeployDir); - Task outputTask = null; - try - { - await using (var buildProcess = ProcessExecutor.LaunchProcess( - dotnetPath, - shortenedPath, - $"run -c Release --project OpenDreamPackageTool -- --tgs -o {shortenedDeployPath}", - null, - true, - true)) - { - using (cancellationToken.Register(() => buildProcess.Terminate())) - buildExitCode = await buildProcess.Lifetime; - - Logger.LogTrace("OD build complete, waiting for output..."); - - outputTask = buildProcess - .GetCombinedOutput(CancellationToken.None); // DCT: Special tactics because of a (dotnet? https://github.com/dotnet/runtime/issues/28583) bug - - await outputTask.WaitAsync(cancellationToken); - } - } - finally - { - if (outputTask != null) - { - if (!outputTask.IsCompleted) - await Task.Yield(); - if (outputTask.IsCompleted) - Logger.LogDebug( - "OpenDream build exited with code {exitCode}:{newLine}{output}", - buildExitCode, - Environment.NewLine, - await outputTask); - } - } + await using var buildProcess = ProcessExecutor.LaunchProcess( + dotnetPath, + shortenedPath, + $"run -c Release --project OpenDreamPackageTool -- --tgs -o {shortenedDeployPath}", + null, + true, + true); + using (cancellationToken.Register(() => buildProcess.Terminate())) + buildExitCode = await buildProcess.Lifetime; + + Logger.LogTrace("OD build complete, waiting for output..."); + + Logger.LogDebug( + "OpenDream build exited with code {exitCode}:{newLine}{output}", + buildExitCode, + Environment.NewLine, + await buildProcess.GetCombinedOutput(cancellationToken)); }, sourcePath, cancellationToken); diff --git a/src/Tgstation.Server.Host/System/IProcess.cs b/src/Tgstation.Server.Host/System/IProcess.cs index dc9a1d5eac5..8df102b2b2a 100644 --- a/src/Tgstation.Server.Host/System/IProcess.cs +++ b/src/Tgstation.Server.Host/System/IProcess.cs @@ -23,12 +23,13 @@ interface IProcess : IProcessBase, IAsyncDisposable /// Get the stderr and stdout output of the . /// /// The for the operation. - /// A resulting in the stderr and stdout output of the . + /// A resulting in the stderr and stdout output of the . /// /// To guarantee that all data is received from the when redirecting streams to a file /// the result of this function must be ed before is called. + /// May call internally if the process has exited. /// - Task GetCombinedOutput(CancellationToken cancellationToken); + ValueTask GetCombinedOutput(CancellationToken cancellationToken); /// /// Asycnhronously terminates the process. diff --git a/src/Tgstation.Server.Host/System/Process.cs b/src/Tgstation.Server.Host/System/Process.cs index 0bc76ce03f8..003f3b12e4a 100644 --- a/src/Tgstation.Server.Host/System/Process.cs +++ b/src/Tgstation.Server.Host/System/Process.cs @@ -7,6 +7,7 @@ using Microsoft.Win32.SafeHandles; using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.System { @@ -27,6 +28,11 @@ sealed class Process : IProcess /// readonly IProcessFeatures processFeatures; + /// + /// The for the . + /// + readonly IAsyncDelayer asyncDelayer; + /// /// The for the . /// @@ -53,10 +59,16 @@ sealed class Process : IProcess /// readonly Task readTask; + /// + /// If the was disposed. + /// + volatile int disposed; + /// /// Initializes a new instance of the class. /// /// The value of . + /// The value of . /// The value of . /// The override value of . /// The value of . @@ -64,6 +76,7 @@ sealed class Process : IProcess /// If was NOT just created. public Process( IProcessFeatures processFeatures, + IAsyncDelayer asyncDelayer, global::System.Diagnostics.Process handle, CancellationTokenSource readerCts, Task readTask, @@ -79,6 +92,7 @@ public Process( cancellationTokenSource = readerCts ?? new CancellationTokenSource(); this.processFeatures = processFeatures ?? throw new ArgumentNullException(nameof(processFeatures)); + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.readTask = readTask; @@ -114,6 +128,9 @@ public Process( /// public async ValueTask DisposeAsync() { + if (Interlocked.Exchange(ref disposed, 1) == 1) + return; + logger.LogTrace("Disposing PID {pid}...", Id); cancellationTokenSource.Cancel(); cancellationTokenSource.Dispose(); @@ -127,12 +144,25 @@ public async ValueTask DisposeAsync() } /// - public Task GetCombinedOutput(CancellationToken cancellationToken) + public async ValueTask GetCombinedOutput(CancellationToken cancellationToken) { if (readTask == null) throw new InvalidOperationException("Output/Error stream reading was not enabled!"); - return readTask.WaitAsync(cancellationToken); + // workaround for https://github.com/dotnet/runtime/issues/28583 (?) + if (handle.HasExited) + { + handle.WaitForExit(); + await Task.WhenAny(readTask, asyncDelayer.Delay(TimeSpan.FromSeconds(10), cancellationToken)); + + if (!readTask.IsCompleted) + { + logger.LogWarning("Detected process output read hang on PID {pid}! Closing handle as a workaround...", Id); + await DisposeAsync(); + } + } + + return await readTask.WaitAsync(cancellationToken); } /// diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index e680b092566..abe50636843 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging; using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.System { @@ -23,6 +24,11 @@ sealed class ProcessExecutor : IProcessExecutor /// readonly IProcessFeatures processFeatures; + /// + /// The for the . + /// + readonly IAsyncDelayer asyncDelayer; + /// /// The for the . /// @@ -59,16 +65,19 @@ public static void WithProcessLaunchExclusivity(Action action) /// Initializes a new instance of the class. ///
/// The value of . + /// The value of . /// The value of . /// The value of . /// The value of . public ProcessExecutor( IProcessFeatures processFeatures, + IAsyncDelayer asyncDelayer, IIOManager ioManager, ILogger logger, ILoggerFactory loggerFactory) { this.processFeatures = processFeatures ?? throw new ArgumentNullException(nameof(processFeatures)); + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); @@ -169,6 +178,7 @@ public IProcess LaunchProcess( var process = new Process( processFeatures, + asyncDelayer, handle, disposeCts, readTask, @@ -302,6 +312,7 @@ Process CreateFromExistingHandle(global::System.Diagnostics.Process handle) var pid = handle.Id; return new Process( processFeatures, + asyncDelayer, handle, null, null, diff --git a/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs b/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs index d70881cdabe..407145730cc 100644 --- a/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs +++ b/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs @@ -60,6 +60,7 @@ public async Task TestSignalListening() new Lazy(() => processExecutor), new DefaultIOManager(), loggerFactory.CreateLogger()), + new AsyncDelayer(), Mock.Of(), loggerFactory.CreateLogger(), loggerFactory); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index fcc38a52c38..ed4a0e544d6 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -39,6 +39,7 @@ using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; +using Tgstation.Server.Host.Utils; using static NuGet.Frameworks.FrameworkConstants; @@ -711,6 +712,7 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? new WindowsProcessFeatures(Mock.Of>()) : new PosixProcessFeatures(new Lazy(() => executor), Mock.Of(), Mock.Of>()), + Mock.Of(), Mock.Of(), Mock.Of>(), LoggerFactory.Create(x => { })); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index dfe2b6028bc..2199658c7e3 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -42,6 +42,7 @@ using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.System; +using Tgstation.Server.Host.Utils; using Tgstation.Server.Tests.Live.Instance; namespace Tgstation.Server.Tests.Live @@ -1075,6 +1076,7 @@ await ioManager.CopyDirectory( new PlatformIdentifier().IsWindows ? new WindowsProcessFeatures(loggerFactory.CreateLogger()) : new PosixProcessFeatures(new Lazy(() => processExecutor), ioManager, loggerFactory.CreateLogger()), + new AsyncDelayer(), ioManager, loggerFactory.CreateLogger(), loggerFactory); diff --git a/tests/Tgstation.Server.Tests/TestSystemInteraction.cs b/tests/Tgstation.Server.Tests/TestSystemInteraction.cs index 92e7aaee008..1075b698d3e 100644 --- a/tests/Tgstation.Server.Tests/TestSystemInteraction.cs +++ b/tests/Tgstation.Server.Tests/TestSystemInteraction.cs @@ -10,6 +10,7 @@ using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; +using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Tests { @@ -23,6 +24,7 @@ public async Task TestScriptExecutionWithStdRead() var platformIdentifier = new PlatformIdentifier(); var processExecutor = new ProcessExecutor( Mock.Of(), + Mock.Of(), new DefaultIOManager(), Mock.Of>(), loggerFactory); @@ -47,6 +49,7 @@ public async Task TestScriptExecutionWithFileOutput() var platformIdentifier = new PlatformIdentifier(); var processExecutor = new ProcessExecutor( Mock.Of(), + Mock.Of(), new DefaultIOManager(), Mock.Of>(), loggerFactory); diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index eb0acb0b76e..1cd8970283c 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -32,6 +32,7 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Api.Models; using Tgstation.Server.Tests.Live; +using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Tests { @@ -207,6 +208,7 @@ await CachingFileDownloader.InitializeByondVersion( new Lazy(() => null), Mock.Of(), loggerFactory.CreateLogger()), + Mock.Of(), Mock.Of(), loggerFactory.CreateLogger(), loggerFactory); From 69774722fbe465ca1f3be80df11ce04ff46bb720 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 17 Nov 2023 08:19:21 -0500 Subject: [PATCH 183/717] These environment variables are preventing SDK detection from working properly under test. Delete them --- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 2199658c7e3..8225e19ebde 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -181,6 +181,10 @@ static ushort FreeTcpPort(params ushort[] usedPorts) [ClassInitialize] public static async Task Initialize(TestContext _) { + // Clear problematic environment variables + Environment.SetEnvironmentVariable("MSBuildExtensionsPath", null); + Environment.SetEnvironmentVariable("MSBuildSDKsPath", null); + if (TestingUtils.RunningInGitHubActions || String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"))) await TestingGitHubService.InitializeAndInject(default); From 85aa8d0f93d5a091803fa0e90698bf7cf2eab2e4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 17 Nov 2023 08:58:29 -0500 Subject: [PATCH 184/717] Simplify a name --- .../Models/Response/EngineInstallResponse.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Api/Models/Response/EngineInstallResponse.cs b/src/Tgstation.Server.Api/Models/Response/EngineInstallResponse.cs index 95d52002395..d4d953c8305 100644 --- a/src/Tgstation.Server.Api/Models/Response/EngineInstallResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/EngineInstallResponse.cs @@ -6,7 +6,7 @@ public sealed class EngineInstallResponse : FileTicketResponse { /// - /// The being used to install a new . + /// The being used to install a new . /// [ResponseOptions] public JobResponse? InstallJob { get; set; } From e24d4d995b0b8e18495fe13f8d5097d04176b22d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 17 Nov 2023 09:07:11 -0500 Subject: [PATCH 185/717] Clean up points where we `TellWorldToReboot()` Making sure we allow `WatchdogStatus.Restoring` where possible. --- .../Live/Instance/WatchdogTest.cs | 35 ++++++++++--------- .../Live/TestLiveServer.cs | 13 ++----- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index ed4a0e544d6..bfc2d898675 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -304,7 +304,7 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) var expectedStaged = currentStatus.StagedCompileJob; Assert.AreNotEqual(expectedStaged.Id, currentStatus.ActiveCompileJob.Id); - await TellWorldToReboot(cancellationToken); + await TellWorldToReboot(false, cancellationToken); currentStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.AreEqual(expectedStaged.Id, currentStatus.ActiveCompileJob.Id); @@ -330,17 +330,7 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) expectedStaged = currentStatus.StagedCompileJob; Assert.AreNotEqual(expectedStaged.Id, currentStatus.ActiveCompileJob.Id); - await TellWorldToReboot(cancellationToken); - - if (testVersion.Engine == EngineType.OpenDream) - do - { - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); - currentStatus = await instanceClient.DreamDaemon.Read(cancellationToken); - } - while (currentStatus.Status == WatchdogStatus.Restoring); - else - currentStatus = await instanceClient.DreamDaemon.Read(cancellationToken); + currentStatus = await TellWorldToReboot(false, cancellationToken); Assert.AreEqual(WatchdogStatus.Online, currentStatus.Status); Assert.IsNull(currentStatus.StagedCompileJob); @@ -1111,7 +1101,7 @@ async Task RunLongRunningTestThenUpdate(CancellationToken cancellationToken) Assert.AreEqual(DreamDaemonSecurity.Safe, newerCompileJob.MinimumSecurityLevel); await CheckDMApiFail(daemonStatus.ActiveCompileJob, cancellationToken); - daemonStatus = await TellWorldToReboot(cancellationToken); + daemonStatus = await TellWorldToReboot(false, cancellationToken); Assert.AreNotEqual(initialCompileJob.Id, daemonStatus.ActiveCompileJob.Id); Assert.IsNull(daemonStatus.StagedCompileJob); @@ -1156,7 +1146,7 @@ async Task RunLongRunningTestThenUpdateWithNewDme(CancellationToken cancellation Assert.AreEqual(DreamDaemonSecurity.Safe, newerCompileJob.MinimumSecurityLevel); await CheckDMApiFail(daemonStatus.ActiveCompileJob, cancellationToken); - daemonStatus = await TellWorldToReboot(cancellationToken); + daemonStatus = await TellWorldToReboot(true, cancellationToken); Assert.AreNotEqual(initialCompileJob.Id, daemonStatus.ActiveCompileJob.Id); Assert.IsNull(daemonStatus.StagedCompileJob); @@ -1220,7 +1210,7 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken Assert.AreEqual(true, daemonStatus.SoftRestart); await CheckDMApiFail(daemonStatus.ActiveCompileJob, cancellationToken); - daemonStatus = await TellWorldToReboot(cancellationToken); + daemonStatus = await TellWorldToReboot(true, cancellationToken); Assert.AreEqual(versionToInstall, daemonStatus.ActiveCompileJob.EngineVersion); Assert.IsNull(daemonStatus.StagedCompileJob); @@ -1290,8 +1280,9 @@ bool KillDD(bool require) return ddProc != null; } - public Task TellWorldToReboot(CancellationToken cancellationToken) => TellWorldToReboot2(instanceClient, topicClient, FindTopicPort(), cancellationToken); - public static async Task TellWorldToReboot2(IInstanceClient instanceClient, ITopicClient topicClient, ushort topicPort, CancellationToken cancellationToken) + public Task TellWorldToReboot(bool allowRestoring, CancellationToken cancellationToken) + => TellWorldToReboot2(instanceClient, topicClient, FindTopicPort(), allowRestoring ? true : testVersion.Engine.Value == EngineType.OpenDream, cancellationToken); + public static async Task TellWorldToReboot2(IInstanceClient instanceClient, ITopicClient topicClient, ushort topicPort, bool allowRestoring, CancellationToken cancellationToken) { var daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.IsNotNull(daemonStatus.StagedCompileJob); @@ -1318,6 +1309,16 @@ public static async Task TellWorldToReboot2(IInstanceClient await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken); + if (allowRestoring && daemonStatus.Status == WatchdogStatus.Restoring) + { + do + { + await Task.Delay(TimeSpan.FromSeconds(1), tempToken); + daemonStatus = await instanceClient.DreamDaemon.Read(tempToken); + } + while (daemonStatus.Status == WatchdogStatus.Restoring); + } + return daemonStatus; } diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 8225e19ebde..e44020cf716 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1583,9 +1583,8 @@ await FailFast( Assert.AreEqual(connectedChannelCount, channelsPresent); - await WatchdogTest.TellWorldToReboot2(instanceClient, WatchdogTest.StaticTopicClient, mainDDPort, cancellationToken); + dd = await WatchdogTest.TellWorldToReboot2(instanceClient, WatchdogTest.StaticTopicClient, mainDDPort, false, cancellationToken); - dd = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value); // if this assert fails, you likely have to crack open the debugger and read test_fail_reason.txt manually Assert.IsNull(dd.StagedCompileJob); Assert.AreEqual(initialStaged, dd.ActiveCompileJob.Id); @@ -1653,13 +1652,7 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) Assert.AreEqual(dd.StagedCompileJob.Job.Id, compileJob.Id); expectedCompileJobId = compileJob.Id.Value; - dd = await wdt.TellWorldToReboot(cancellationToken); - - while (dd.Status.Value == WatchdogStatus.Restoring) - { - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); - dd = await instanceClient.DreamDaemon.Read(cancellationToken); - } + dd = await wdt.TellWorldToReboot(false, cancellationToken); Assert.AreEqual(dd.ActiveCompileJob.Job.Id, expectedCompileJobId); Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value); @@ -1696,7 +1689,7 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest Assert.AreEqual(expectedStaged, currentDD.StagedCompileJob.Job.Id.Value); var wdt = new WatchdogTest(edgeVersion, instanceClient, GetInstanceManager(), (ushort)server.ApiUrl.Port, server.HighPriorityDreamDaemon, mainDDPort, server.UsingBasicWatchdog); - currentDD = await wdt.TellWorldToReboot(cancellationToken); + currentDD = await wdt.TellWorldToReboot(true, cancellationToken); Assert.AreEqual(expectedStaged, currentDD.ActiveCompileJob.Job.Id.Value); Assert.IsNull(currentDD.StagedCompileJob); From a4bf9e409bc1de75ae964e2faafe419fbffbdcb4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 17 Nov 2023 11:02:11 -0500 Subject: [PATCH 186/717] Remove deprecated API fields Closes #1718 --- src/Tgstation.Server.Api/ApiHeaders.cs | 4 +--- .../Models/ChatChannel.cs | 21 ++----------------- .../Models/Internal/ChatBotApiBase.cs | 6 ++---- .../Models/Internal/DreamDaemonApiBase.cs | 21 +------------------ .../Models/Request/RepositoryCreateRequest.cs | 6 ------ .../Models/Response/TokenResponse.cs | 10 +-------- .../Controllers/ChatController.cs | 4 ---- .../Controllers/DreamDaemonController.cs | 12 ----------- .../Controllers/RepositoryController.cs | 4 ---- .../Models/ChatChannel.cs | 8 ++----- .../Security/TokenFactory.cs | 3 --- .../Live/Instance/ChatTest.cs | 14 ------------- .../Live/Instance/WatchdogTest.cs | 14 +++---------- .../Live/RawRequestTests.cs | 3 --- 14 files changed, 12 insertions(+), 118 deletions(-) diff --git a/src/Tgstation.Server.Api/ApiHeaders.cs b/src/Tgstation.Server.Api/ApiHeaders.cs index 01e61cb373b..fad13a03305 100644 --- a/src/Tgstation.Server.Api/ApiHeaders.cs +++ b/src/Tgstation.Server.Api/ApiHeaders.cs @@ -287,9 +287,7 @@ void AddError(HeaderErrorTypes headerType, string message) try { -#pragma warning disable CS0618 // Type or member is obsolete - Token.ExpiresAt = Token.ParseJwt().ValidTo; -#pragma warning restore CS0618 // Type or member is obsolete + Token.ParseJwt(); } catch (ArgumentException ex) when (ex is not ArgumentNullException) { diff --git a/src/Tgstation.Server.Api/Models/ChatChannel.cs b/src/Tgstation.Server.Api/Models/ChatChannel.cs index 07b643fcab5..3192603e2b0 100644 --- a/src/Tgstation.Server.Api/Models/ChatChannel.cs +++ b/src/Tgstation.Server.Api/Models/ChatChannel.cs @@ -1,5 +1,4 @@ -using System; -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; using Tgstation.Server.Api.Models.Internal; @@ -11,28 +10,12 @@ namespace Tgstation.Server.Api.Models public class ChatChannel : ChatChannelBase { /// - /// The channel identifier. Supercedes and . + /// The channel identifier. /// For , it's the IRC channel name and optional password colon separated. /// For , it's the stringified Discord channel snowflake. /// [Required] [StringLength(Limits.MaximumIndexableStringLength, MinimumLength = 1)] public string? ChannelData { get; set; } - - /// - /// The IRC channel name. Also potentially contains the channel passsword (if separated by a colon). - /// If multiple copies of the same channel with different keys are added to the server, the one that will be used is undefined. - /// - [ResponseOptions] - [StringLength(Limits.MaximumIndexableStringLength, MinimumLength = 1)] - [Obsolete($"Use {nameof(ChannelData)}")] - public string? IrcChannel { get; set; } - - /// - /// The Discord channel ID. - /// - [Obsolete($"Use {nameof(ChannelData)}")] - [ResponseOptions] - public ulong? DiscordChannelId { get; set; } } } diff --git a/src/Tgstation.Server.Api/Models/Internal/ChatBotApiBase.cs b/src/Tgstation.Server.Api/Models/Internal/ChatBotApiBase.cs index 231a94ffbe5..e490c8e5fb1 100644 --- a/src/Tgstation.Server.Api/Models/Internal/ChatBotApiBase.cs +++ b/src/Tgstation.Server.Api/Models/Internal/ChatBotApiBase.cs @@ -22,10 +22,8 @@ public bool ValidateProviderChannelTypes() return true; return Provider.Value switch { -#pragma warning disable CS0618 - ChatProvider.Discord => Channels?.Select(x => (x.DiscordChannelId.HasValue || ulong.TryParse(x.ChannelData, out _)) && x.IrcChannel == null).All(x => x) ?? true, - ChatProvider.Irc => Channels?.Select(x => !x.DiscordChannelId.HasValue && (x.IrcChannel != null || x.ChannelData != null)).All(x => x) ?? true, -#pragma warning restore CS0618 + ChatProvider.Discord => Channels?.All(x => UInt64.TryParse(x.ChannelData, out _)) ?? true, + ChatProvider.Irc => Channels?.All(x => x.ChannelData != null && x.ChannelData[0] == '#') ?? true, _ => throw new InvalidOperationException("Invalid provider type!"), }; } diff --git a/src/Tgstation.Server.Api/Models/Internal/DreamDaemonApiBase.cs b/src/Tgstation.Server.Api/Models/Internal/DreamDaemonApiBase.cs index 50de44e64b7..6afac0db9ac 100644 --- a/src/Tgstation.Server.Api/Models/Internal/DreamDaemonApiBase.cs +++ b/src/Tgstation.Server.Api/Models/Internal/DreamDaemonApiBase.cs @@ -1,7 +1,4 @@ -using System; -using System.ComponentModel.DataAnnotations; - -namespace Tgstation.Server.Api.Models.Internal +namespace Tgstation.Server.Api.Models.Internal { /// /// Base class for DreamDaemon API models. @@ -19,21 +16,5 @@ public abstract class DreamDaemonApiBase : DreamDaemonSettings /// [ResponseOptions] public bool? SoftShutdown { get; set; } - - /// - /// Deprecated, use . - /// - [Required] - [ResponseOptions] - [Obsolete("Use HealthCheckSeconds")] - public uint? HeartbeatSeconds { get; set; } - - /// - /// Deprecated, use . - /// - [Required] - [ResponseOptions] - [Obsolete("Use DumpOnHealthCheckRestart")] - public bool? DumpOnHeartbeatRestart { get; set; } } } diff --git a/src/Tgstation.Server.Api/Models/Request/RepositoryCreateRequest.cs b/src/Tgstation.Server.Api/Models/Request/RepositoryCreateRequest.cs index dded782d643..a29ba1b674c 100644 --- a/src/Tgstation.Server.Api/Models/Request/RepositoryCreateRequest.cs +++ b/src/Tgstation.Server.Api/Models/Request/RepositoryCreateRequest.cs @@ -14,11 +14,5 @@ public sealed class RepositoryCreateRequest : RepositoryApiBase ///
[RequestOptions(FieldPresence.Required)] public Uri? Origin { get; set; } - - /// - /// If submodules should be recursively cloned. Note that further updates are not recursive. - /// - [Obsolete("Use updateSubmodules instead.")] - public bool? RecurseSubmodules { get; set; } } } diff --git a/src/Tgstation.Server.Api/Models/Response/TokenResponse.cs b/src/Tgstation.Server.Api/Models/Response/TokenResponse.cs index 8f7b01762b8..c3908e95185 100644 --- a/src/Tgstation.Server.Api/Models/Response/TokenResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/TokenResponse.cs @@ -1,6 +1,4 @@ -using System; - -using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.JsonWebTokens; namespace Tgstation.Server.Api.Models.Response { @@ -14,12 +12,6 @@ public sealed class TokenResponse ///
public string? Bearer { get; set; } - /// - /// When the expires. - /// - [Obsolete("Will be removed in a future API version")] - public DateTimeOffset? ExpiresAt { get; set; } - /// /// Parses the as a . /// diff --git a/src/Tgstation.Server.Host/Controllers/ChatController.cs b/src/Tgstation.Server.Host/Controllers/ChatController.cs index 7f9682c43aa..967971eb248 100644 --- a/src/Tgstation.Server.Host/Controllers/ChatController.cs +++ b/src/Tgstation.Server.Host/Controllers/ChatController.cs @@ -69,10 +69,6 @@ static Models.ChatChannel ConvertApiChatChannel(Api.Models.ChatChannel api, Chat { var result = new Models.ChatChannel { -#pragma warning disable CS0618 - DiscordChannelId = api.DiscordChannelId, - IrcChannel = api.IrcChannel, -#pragma warning restore CS0618 IsAdminChannel = api.IsAdminChannel ?? false, IsWatchdogChannel = api.IsWatchdogChannel ?? false, IsUpdatesChannel = api.IsUpdatesChannel ?? false, diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index 8e57d022c5d..24747e2fee3 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -184,14 +184,6 @@ public async ValueTask Update([FromBody] DreamDaemonRequest model return Conflict(new ErrorMessageResponse(ErrorCode.PortNotAvailable)); } -#pragma warning disable CS0618 // Type or member is obsolete - if (model.HeartbeatSeconds.HasValue && !model.HealthCheckSeconds.HasValue) - model.HealthCheckSeconds = model.HeartbeatSeconds; - - if (model.DumpOnHeartbeatRestart.HasValue && !model.DumpOnHealthCheckRestart.HasValue) - model.DumpOnHealthCheckRestart = model.DumpOnHeartbeatRestart; -#pragma warning restore CS0618 // Type or member is obsolete - var userRights = (DreamDaemonRights)AuthenticationContext.GetRight(RightsType.DreamDaemon); bool CheckModified(Expression> expression, DreamDaemonRights requiredRight) @@ -356,10 +348,6 @@ ValueTask ReadImpl(DreamDaemonSettings settings, CancellationToke result.StartupTimeout = settings.StartupTimeout.Value; result.HealthCheckSeconds = settings.HealthCheckSeconds.Value; result.DumpOnHealthCheckRestart = settings.DumpOnHealthCheckRestart.Value; -#pragma warning disable CS0618 // Type or member is obsolete - result.HeartbeatSeconds = settings.HealthCheckSeconds.Value; - result.DumpOnHeartbeatRestart = settings.DumpOnHealthCheckRestart.Value; -#pragma warning restore CS0618 // Type or member is obsolete result.TopicRequestTimeout = settings.TopicRequestTimeout.Value; result.AdditionalParameters = settings.AdditionalParameters; result.StartProfiler = settings.StartProfiler; diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs index 37766ce0fd1..6bc447a0449 100644 --- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs +++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs @@ -99,10 +99,6 @@ public async ValueTask Create([FromBody] RepositoryCreateRequest || ((model.CommitterEmail ?? model.CommitterName) != null && !userRights.HasFlag(RepositoryRights.ChangeCommitter))) return Forbid(); - #pragma warning disable CS0618 // Support for obsolete API field - model.UpdateSubmodules ??= model.RecurseSubmodules; - #pragma warning restore CS0618 - var currentModel = await DatabaseContext .RepositorySettings .AsQueryable() diff --git a/src/Tgstation.Server.Host/Models/ChatChannel.cs b/src/Tgstation.Server.Host/Models/ChatChannel.cs index 8519ffffdbb..a4cbea0952a 100644 --- a/src/Tgstation.Server.Host/Models/ChatChannel.cs +++ b/src/Tgstation.Server.Host/Models/ChatChannel.cs @@ -20,13 +20,13 @@ public sealed class ChatChannel : ChatChannelBase public long ChatSettingsId { get; set; } /// - /// See . + /// The IRC channel name. /// [StringLength(Limits.MaximumIndexableStringLength, MinimumLength = 1)] public string IrcChannel { get; set; } /// - /// See . + /// The Discord channel snowflake. /// public ulong? DiscordChannelId { get; set; } @@ -43,10 +43,6 @@ public sealed class ChatChannel : ChatChannelBase public Api.Models.ChatChannel ToApi(ChatProvider chatProvider) => new Api.Models.ChatChannel { ChannelData = chatProvider == ChatProvider.Discord ? DiscordChannelId.Value.ToString(CultureInfo.InvariantCulture) : IrcChannel, -#pragma warning disable CS0618 - IrcChannel = IrcChannel, - DiscordChannelId = DiscordChannelId, -#pragma warning restore CS0618 IsAdminChannel = IsAdminChannel, IsWatchdogChannel = IsWatchdogChannel, IsUpdatesChannel = IsUpdatesChannel, diff --git a/src/Tgstation.Server.Host/Security/TokenFactory.cs b/src/Tgstation.Server.Host/Security/TokenFactory.cs index c45a282e2ae..cc18c3298a4 100644 --- a/src/Tgstation.Server.Host/Security/TokenFactory.cs +++ b/src/Tgstation.Server.Host/Security/TokenFactory.cs @@ -119,13 +119,10 @@ public TokenResponse CreateToken(Models.User user, bool oAuth) expiry.UtcDateTime, now.UtcDateTime)); -#pragma warning disable CS0618 // Type or member is obsolete var tokenResponse = new TokenResponse { Bearer = tokenHandler.WriteToken(securityToken), - ExpiresAt = expiry, }; -#pragma warning restore CS0618 // Type or member is obsolete return tokenResponse; } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ChatTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ChatTest.cs index 3162ceb5889..0963b72b4fb 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ChatTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ChatTest.cs @@ -122,9 +122,6 @@ async Task RunIrc(CancellationToken cancellationToken) IsSystemChannel = true, Tag = "butt2", ChannelData = channelId, -#pragma warning disable CS0618 - IrcChannel = "should_not_be_this!!!JHF*WW(#*(*$&(#*@))(" -#pragma warning restore CS0618 } } }, cancellationToken); @@ -137,10 +134,6 @@ async Task RunIrc(CancellationToken cancellationToken) Assert.AreEqual(true, updatedBot.Channels.First().IsUpdatesChannel); Assert.AreEqual(true, updatedBot.Channels.First().IsWatchdogChannel); Assert.AreEqual("butt2", updatedBot.Channels.First().Tag); -#pragma warning disable CS0618 - Assert.AreEqual(channelId, updatedBot.Channels.First().IrcChannel); - Assert.IsNull(updatedBot.Channels.First().DiscordChannelId); -#pragma warning restore CS0618 Assert.AreEqual(channelId, updatedBot.Channels.First().ChannelData); } @@ -224,9 +217,6 @@ async Task RunDiscord(CancellationToken cancellationToken) IsSystemChannel = true, Tag = "butt", ChannelData = channelId.ToString(), -#pragma warning disable CS0618 - DiscordChannelId = 1234, -#pragma warning restore CS0618 } } }, cancellationToken); @@ -239,10 +229,6 @@ async Task RunDiscord(CancellationToken cancellationToken) Assert.AreEqual(true, updatedBot.Channels.First().IsUpdatesChannel); Assert.AreEqual(true, updatedBot.Channels.First().IsWatchdogChannel); Assert.AreEqual("butt", updatedBot.Channels.First().Tag); -#pragma warning disable CS0618 - Assert.AreEqual(channelId, updatedBot.Channels.First().DiscordChannelId); - Assert.IsNull(updatedBot.Channels.First().IrcChannel); -#pragma warning restore CS0618 Assert.AreEqual(channelId.ToString(), updatedBot.Channels.First().ChannelData); } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 4eaca9ab598..97c629b0bca 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -617,24 +617,20 @@ void TestLinuxIsntBeingFuckingCheekyAboutFilePaths(DreamDaemonResponse currentSt async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToken) { System.Console.WriteLine("TEST: WATCHDOG HEALTH CHECK TEST"); -#pragma warning disable CS0618 // Type or member is obsolete + // Check reverse mapping var status = await instanceClient.DreamDaemon.Update(new DreamDaemonRequest { DumpOnHealthCheckRestart = !checkDump, }, cancellationToken); - Assert.AreEqual(!checkDump, status.DumpOnHeartbeatRestart); - // enable health checks status = await instanceClient.DreamDaemon.Update(new DreamDaemonRequest { HealthCheckSeconds = 1, - DumpOnHeartbeatRestart = checkDump, + DumpOnHealthCheckRestart = checkDump, }, cancellationToken); - Assert.AreEqual(checkDump, status.DumpOnHeartbeatRestart); -#pragma warning restore CS0618 // Type or member is obsolete Assert.AreEqual(checkDump, status.DumpOnHealthCheckRestart); var startJob = await StartDD(cancellationToken); @@ -692,8 +688,6 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); ddStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.AreEqual(1U, ddStatus.HealthCheckSeconds.Value); -#pragma warning disable CS0618 // Type or member is obsolete - Assert.AreEqual(1U, ddStatus.HeartbeatSeconds.Value); if (ddStatus.Status.Value == WatchdogStatus.Offline) { await CheckDMApiFail(ddStatus.ActiveCompileJob, cancellationToken); @@ -708,11 +702,9 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest // disable health checks ddStatus = await instanceClient.DreamDaemon.Update(new DreamDaemonRequest { - HeartbeatSeconds = 0, + HealthCheckSeconds = 0, }, cancellationToken); Assert.AreEqual(0U, ddStatus.HealthCheckSeconds.Value); - Assert.AreEqual(0U, ddStatus.HeartbeatSeconds.Value); -#pragma warning restore CS0618 // Type or member is obsolete if (checkDump) { diff --git a/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs b/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs index 50e9b211692..3e20609e600 100644 --- a/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs +++ b/tests/Tgstation.Server.Tests/Live/RawRequestTests.cs @@ -210,13 +210,10 @@ static async Task TestServerInformation(IServerClientFactory clientFactory, ISer Assert.AreEqual(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), serverInfo.WindowsHost); //check that modifying the token even slightly fucks up the auth -#pragma warning disable CS0618 // Type or member is obsolete var newToken = new TokenResponse { - ExpiresAt = serverClient.Token.ExpiresAt, Bearer = serverClient.Token.Bearer + '0' }; -#pragma warning restore CS0618 // Type or member is obsolete var badClient = clientFactory.CreateFromToken(serverClient.Url, newToken); await ApiAssert.ThrowsException(() => badClient.Administration.Read(cancellationToken)); From 08f1a1ebf79958f486ebd263049391dced3b5751 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 17 Nov 2023 12:26:34 -0500 Subject: [PATCH 187/717] This test doesn't apply to OD --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index bfc2d898675..3a6d08dad88 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -623,7 +623,7 @@ async Task RunBasicTest(CancellationToken cancellationToken) void TestLinuxIsntBeingFuckingCheekyAboutFilePaths(DreamDaemonResponse currentStatus, CompileJobResponse previousStatus) { - if (new PlatformIdentifier().IsWindows || usingBasicWatchdog) + if (new PlatformIdentifier().IsWindows || usingBasicWatchdog || currentStatus.ActiveCompileJob.EngineVersion.Engine.Value == EngineType.OpenDream) return; Assert.IsNotNull(currentStatus.ActiveCompileJob); From fab05fdafc13d8dd86ac6bfa5e587ac727f76fd2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 17 Nov 2023 21:41:22 -0500 Subject: [PATCH 188/717] Fix misuse of OD logging cvars --- .../Components/Engine/IEngineInstallation.cs | 2 +- .../Components/Engine/OpenDreamInstallation.cs | 11 ++++++++++- .../Components/Engine/OpenDreamInstaller.cs | 1 + .../Components/Session/SessionControllerFactory.cs | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs index af111b9a158..f9aecca33b3 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs @@ -53,7 +53,7 @@ public interface IEngineInstallation /// The . /// The map of parameter s as a . Should NOT include the of . /// The . - /// The path to the log file, if any. + /// The full path to the log file, if any. /// The formatted arguments . string FormatServerArguments( IDmbProvider dmbProvider, diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index 89546436015..254861e69a6 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -5,6 +5,7 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.IO; namespace Tgstation.Server.Host.Components.Engine { @@ -34,19 +35,27 @@ sealed class OpenDreamInstallation : EngineInstallationBase /// public override Task InstallationTask { get; } + /// + /// The for the . + /// + readonly IIOManager ioManager; + /// /// Initializes a new instance of the class. /// + /// The value of . /// The value of . /// The value of . /// The value of . /// The value of . public OpenDreamInstallation( + IIOManager ioManager, string serverExePath, string compilerExePath, Task installationTask, EngineVersion version) { + this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); ServerExePath = serverExePath ?? throw new ArgumentNullException(nameof(serverExePath)); CompilerExePath = compilerExePath ?? throw new ArgumentNullException(nameof(compilerExePath)); InstallationTask = installationTask ?? throw new ArgumentNullException(nameof(installationTask)); @@ -70,7 +79,7 @@ public override string FormatServerArguments( var parametersString = EncodeParameters(parameters, launchParameters); var loggingEnabled = logFilePath != null; - var arguments = $"--cvar {(loggingEnabled ? $"log.path=\"{logFilePath}\"" : "log.enabled=false")} --cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" --cvar opendream.json_path=\"./{dmbProvider.DmbName}\""; + var arguments = $"--cvar {(loggingEnabled ? $"log.path=\"{ioManager.GetDirectoryName(logFilePath)}\" --cvar log.format=\"{ioManager.GetFileName(logFilePath)}\"" : "log.enabled=false")} --cvar log.runtimelog=false --cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" --cvar opendream.json_path=\"./{dmbProvider.DmbName}\""; return arguments; } diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index da7a9fae080..1357836c587 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -98,6 +98,7 @@ public override IEngineInstallation CreateInstallation(EngineVersion version, st CheckVersionValidity(version); GetExecutablePaths(path, out var serverExePath, out var compilerExePath); return new OpenDreamInstallation( + IOManager, serverExePath, compilerExePath, installationTask, diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 3670e146b94..9cd7fa15aad 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -474,7 +474,7 @@ public async ValueTask Reattach( /// The . /// The . /// The secure string to use for the session. - /// The path to log DreamDaemon output to. + /// The full path to log DreamDaemon output to. /// If we are only validating the DMAPI then exiting. /// The for the operation. /// A resulting in the DreamDaemon . From dac01b49aba2c5d0296825e12656763cf42f70be Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 17 Nov 2023 23:10:22 -0500 Subject: [PATCH 189/717] Fix calling `TrustDmbPath` on multiple installers --- .../Components/Engine/ByondInstallerBase.cs | 5 ++++- .../Components/Engine/DelegatingEngineInstaller.cs | 5 ++--- .../Components/Engine/EngineInstallerBase.cs | 2 +- src/Tgstation.Server.Host/Components/Engine/EngineManager.cs | 2 +- .../Components/Engine/IEngineInstaller.cs | 3 ++- .../Components/Engine/OpenDreamInstaller.cs | 5 ++++- 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index 217c49afdf9..dcbbd9b0cdc 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -151,8 +151,11 @@ public override async Task CleanCache(CancellationToken cancellationToken) } /// - public override async ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken) + public override async ValueTask TrustDmbPath(EngineVersion version, string fullDmbPath, CancellationToken cancellationToken) { + ArgumentNullException.ThrowIfNull(version); + ArgumentNullException.ThrowIfNull(fullDmbPath); + var byondDir = PathToUserFolder; if (String.IsNullOrWhiteSpace(byondDir)) { diff --git a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs index 4a9c29cd7a2..75393af5b77 100644 --- a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Tgstation.Server.Api.Models; -using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Jobs; namespace Tgstation.Server.Host.Components.Engine @@ -46,8 +45,8 @@ public ValueTask Install(EngineVersion version, string path, CancellationToken c => DelegateCall(version, installer => installer.Install(version, path, cancellationToken)); /// - public ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken) - => ValueTaskExtensions.WhenAll(delegatedInstallers.Values.Select(installer => installer.TrustDmbPath(fullDmbPath, cancellationToken))); + public ValueTask TrustDmbPath(EngineVersion version, string fullDmbPath, CancellationToken cancellationToken) + => DelegateCall(version, installer => installer.TrustDmbPath(version, fullDmbPath, cancellationToken)); /// public ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs index 2b3c986d29d..e281c3f48fc 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs @@ -55,7 +55,7 @@ protected EngineInstallerBase(IIOManager ioManager, ILogger public abstract ValueTask DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken); /// - public abstract ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken); + public abstract ValueTask TrustDmbPath(EngineVersion version, string fullDmbPath, CancellationToken cancellationToken); /// /// Check that a given is of type . diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index 36365332dd3..12051204114 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -176,7 +176,7 @@ public async ValueTask UseExecutables(EngineVersion requi try { if (trustDmbFullPath != null) - await engineInstaller.TrustDmbPath(trustDmbFullPath, cancellationToken); + await engineInstaller.TrustDmbPath(installLock.Version, trustDmbFullPath, cancellationToken); return installLock; } diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs index 3bcd576e8dd..23602025849 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs @@ -50,10 +50,11 @@ interface IEngineInstaller /// /// Add a given to the trusted DMBs list in BYOND's config. /// + /// The being used. /// Full path to the .dmb that should be trusted. /// The for the operation. /// A representing the running operation. - ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken); + ValueTask TrustDmbPath(EngineVersion version, string fullDmbPath, CancellationToken cancellationToken); /// /// Attempts to cleans the engine's cache folder for the system. diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 1357836c587..bbd09ed1c1d 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -289,9 +289,12 @@ public override ValueTask UpgradeInstallation(EngineVersion version, string path } /// - public override ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken) + public override ValueTask TrustDmbPath(EngineVersion engineVersion, string fullDmbPath, CancellationToken cancellationToken) { + ArgumentNullException.ThrowIfNull(engineVersion); ArgumentNullException.ThrowIfNull(fullDmbPath); + + Logger.LogTrace("TrustDmbPath is a no-op: {path}", fullDmbPath); return ValueTask.CompletedTask; } From 2f8e566f130931c3d9840ebdc723b402fb1d1c3f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 17 Nov 2023 23:21:50 -0500 Subject: [PATCH 190/717] Do not use `AdvancedWatchdog` features for non-Byond engines --- .../Components/Watchdog/AdvancedWatchdog.cs | 6 ++++++ .../Components/Watchdog/WindowsWatchdog.cs | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs index 9d8f8cbda82..82de6055599 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; +using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; @@ -290,6 +291,11 @@ protected sealed override async ValueTask PrepServerForLaunch(IDmb throw new InvalidOperationException("Expected pendingSwappable to be null!"); Logger.LogTrace("Prep for server launch"); + if (dmbToUse.EngineVersion.Engine.Value != EngineType.Byond) + { + Logger.LogDebug("Not using SwappableDmbProvider for engine type {engineType}", dmbToUse.EngineVersion.Engine.Value); + return dmbToUse; + } ActiveSwappable = CreateSwappableDmbProvider(dmbToUse); try diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs index 8180630ea49..cd8f0b45255 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging; +using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.Deployment; @@ -80,6 +81,12 @@ public WindowsWatchdog( /// protected override async ValueTask ApplyInitialDmb(CancellationToken cancellationToken) { + if (Server.EngineVersion.Engine.Value != EngineType.Byond) + { + Logger.LogTrace("Not setting InitialDmb for engine type {engineType}", Server.EngineVersion.Engine.Value); + return; + } + Server.ReattachInformation.InitialDmb = await DmbFactory.FromCompileJob(Server.CompileJob, cancellationToken); } From 5746bd92dc27c6390f76c8ba5cbafa378b77ed33 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 18 Nov 2023 21:05:17 -0500 Subject: [PATCH 191/717] More .NET 8 package updates Also remove Pomelo's nightly feed --- NuGet.config | 7 ------- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 8 ++++---- 2 files changed, 4 insertions(+), 11 deletions(-) delete mode 100644 NuGet.config diff --git a/NuGet.config b/NuGet.config deleted file mode 100644 index 95d7e9642f6..00000000000 --- a/NuGet.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 68c56a6d3dc..9890be89d04 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -99,11 +99,11 @@ - + - + - + @@ -125,7 +125,7 @@ - + From 8f51c5fed5f775e6ba3e5e35f4198a49fa396734 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 19 Nov 2023 17:11:10 -0500 Subject: [PATCH 192/717] Add `SessionId` to `DreamDaemonResponse` - Fix race condition with updating launch parameters. - Add additional logging. - Add integration tests --- .../Models/Internal/DreamDaemonApiBase.cs | 6 ++ .../Components/Session/ISessionPersistor.cs | 10 ++- .../Components/Session/SessionPersistor.cs | 35 +++++++- .../Components/Watchdog/AdvancedWatchdog.cs | 2 +- .../Components/Watchdog/BasicWatchdog.cs | 17 +++- .../Components/Watchdog/IWatchdog.cs | 5 ++ .../Components/Watchdog/WatchdogBase.cs | 21 ++--- .../Controllers/DreamDaemonController.cs | 17 +++- .../Models/ReattachInformation.cs | 5 -- .../Models/ReattachInformationBase.cs | 9 ++- .../Live/Instance/WatchdogTest.cs | 79 +++++++++++++------ .../Live/TestLiveServer.cs | 10 ++- 12 files changed, 166 insertions(+), 50 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/Internal/DreamDaemonApiBase.cs b/src/Tgstation.Server.Api/Models/Internal/DreamDaemonApiBase.cs index 6afac0db9ac..6bde7948d03 100644 --- a/src/Tgstation.Server.Api/Models/Internal/DreamDaemonApiBase.cs +++ b/src/Tgstation.Server.Api/Models/Internal/DreamDaemonApiBase.cs @@ -5,6 +5,12 @@ /// public abstract class DreamDaemonApiBase : DreamDaemonSettings { + /// + /// An incrementing ID for representing current server execution. + /// + [ResponseOptions] + public long? SessionId { get; set; } + /// /// If the server is undergoing a soft reset. This may be automatically set by changes to other fields. /// diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs index 9e088bd7b14..5b1f1d72007 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs @@ -11,11 +11,19 @@ public interface ISessionPersistor /// /// Save some . /// - /// The to save. + /// The to save. will be written back into it. /// The for the operation. /// A representing the running operation. ValueTask Save(ReattachInformation reattachInformation, CancellationToken cancellationToken); + /// + /// Update some . + /// + /// The to update. Requires to have been called on it previously or it was retrieved from . + /// The for the operation. + /// A representing the running operation. + ValueTask Update(ReattachInformation reattachInformation, CancellationToken cancellationToken); + /// /// Load a saved . /// diff --git a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs index 5c3819f8bea..e932fa6ec79 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs @@ -69,7 +69,7 @@ public ValueTask Save(ReattachInformation reattachInformation, CancellationToken { ArgumentNullException.ThrowIfNull(reattachInformation); - logger.LogDebug("Saving reattach information: {info}...", reattachInformation); + logger.LogTrace("Saving reattach information: {info}...", reattachInformation); await ClearImpl(db, false, cancellationToken); @@ -87,6 +87,39 @@ public ValueTask Save(ReattachInformation reattachInformation, CancellationToken db.ReattachInformations.Add(dbReattachInfo); await db.Save(cancellationToken); + + reattachInformation.Id = dbReattachInfo.Id.Value; + logger.LogDebug("Saved reattach information: {info}", reattachInformation); + }); + + /// + public ValueTask Update(ReattachInformation reattachInformation, CancellationToken cancellationToken) => databaseContextFactory.UseContextTaskReturn(async db => + { + ArgumentNullException.ThrowIfNull(reattachInformation); + if (!reattachInformation.Id.HasValue) + throw new InvalidOperationException("Provided reattachInformation has no Id!"); + + logger.LogTrace("Updating reattach information: {info}...", reattachInformation); + + var dbReattachInfo = new Models.ReattachInformation + { + Id = reattachInformation.Id.Value, + }; + + db.ReattachInformations.Attach(dbReattachInfo); + + dbReattachInfo.AccessIdentifier = reattachInformation.AccessIdentifier; + dbReattachInfo.CompileJobId = reattachInformation.Dmb.CompileJob.Id.Value; + dbReattachInfo.InitialCompileJobId = reattachInformation.InitialDmb?.CompileJob.Id.Value; + dbReattachInfo.Port = reattachInformation.Port; + dbReattachInfo.ProcessId = reattachInformation.ProcessId; + dbReattachInfo.RebootState = reattachInformation.RebootState; + dbReattachInfo.LaunchSecurityLevel = reattachInformation.LaunchSecurityLevel; + dbReattachInfo.LaunchVisibility = reattachInformation.LaunchVisibility; + + await db.Save(cancellationToken); + + logger.LogDebug("Updated reattach information: {info}", reattachInformation); }); /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs index 7b5ead8ec70..afc801476eb 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs @@ -217,7 +217,7 @@ async Task CleanupLingeringDeployment() ActiveSwappable = pendingSwappable; pendingSwappable = null; - await SessionPersistor.Save(Server.ReattachInformation, cancellationToken); + await SessionPersistor.Update(Server.ReattachInformation, cancellationToken); await updateTask; } else diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index 2fd1d3a5c76..8e437b618fe 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -255,6 +255,11 @@ await ReattachFailure( if (!reattachInProgress) await SessionStartupPersist(cancellationToken); + if (!SessionId.HasValue) + Logger.LogError("Server should have a session ID allocated by now but it doesn't!"); + else + Logger.LogInformation("Watchdog starting session ID {id}", SessionId.Value); + await CheckLaunchResult(Server, "Server", cancellationToken); Server.EnableCustomChatCommands(); @@ -262,7 +267,7 @@ await ReattachFailure( // persist again, because the DMAPI can say we need a different topic port (Original OD behavior) // kinda hacky imo, but at least we can safely forget about this if (!reattachInProgress) - await SessionPersistor.Save(Server.ReattachInformation, cancellationToken); + await SessionPersistor.Update(Server.ReattachInformation, cancellationToken); } catch (Exception ex) { @@ -298,7 +303,15 @@ protected virtual ValueTask SessionStartupPersist(CancellationToken cancellation protected virtual ValueTask HandleNormalReboot(CancellationToken cancellationToken) { var settingsUpdatePending = ActiveLaunchParameters != LastLaunchParameters; - var result = settingsUpdatePending ? MonitorAction.Restart : MonitorAction.Continue; + MonitorAction result; + if (settingsUpdatePending) + { + Logger.LogTrace("There is a settings update pending"); + result = MonitorAction.Restart; + } + else + result = MonitorAction.Continue; + return ValueTask.FromResult(result); } diff --git a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs index 2d8d0f5d240..6ffe3293c0b 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs @@ -14,6 +14,11 @@ namespace Tgstation.Server.Host.Components.Watchdog /// public interface IWatchdog : IComponentService, IAsyncDisposable, IEventConsumer, IRenameNotifyee { + /// + /// An incrementing ID for representing current server execution. + /// + long? SessionId { get; } + /// /// The current . /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index 6048e66f619..33b5ca07201 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -35,6 +35,9 @@ namespace Tgstation.Server.Host.Components.Watchdog #pragma warning disable CA1506 // TODO: Decomplexify abstract class WatchdogBase : IWatchdog, ICustomCommandHandler, IRestartHandler { + /// + public long? SessionId => GetActiveController()?.ReattachInformation.Id; + /// public WatchdogStatus Status { @@ -61,11 +64,6 @@ public WatchdogStatus Status /// public abstract RebootState? RebootState { get; } - /// - /// that completes when are changed and we are running. - /// - protected TaskCompletionSource ActiveParametersUpdated { get; set; } - /// /// The for the . /// @@ -146,6 +144,11 @@ public WatchdogStatus Status ///
readonly bool autoStart; + /// + /// that completes when are changed and we are running. + /// + volatile TaskCompletionSource activeParametersUpdated; + /// /// The for the monitor loop. /// @@ -232,7 +235,7 @@ protected WatchdogBase( ActiveLaunchParameters = initialLaunchParameters; releaseServers = false; - ActiveParametersUpdated = new TaskCompletionSource(); + activeParametersUpdated = new TaskCompletionSource(); restartRegistration = serverControl.RegisterForRestart(this); try @@ -273,8 +276,8 @@ public async ValueTask ChangeSettings(DreamDaemonLaunchParameters launchParamete if (match || Status == WatchdogStatus.Offline) return; - ActiveParametersUpdated.TrySetResult(); // queue an update - ActiveParametersUpdated = new TaskCompletionSource(); + var oldTcs = Interlocked.Exchange(ref activeParametersUpdated, new TaskCompletionSource()); + oldTcs.SetResult(); } } @@ -889,7 +892,7 @@ void TryUpdateTask(ref Task oldTask, Func newTaskFactory) if (!sameController) lastController = controller; - TryUpdateTask(ref activeLaunchParametersChanged, () => ActiveParametersUpdated.Task); + TryUpdateTask(ref activeLaunchParametersChanged, () => activeParametersUpdated.Task); TryUpdateTask( ref newDmbAvailable, () => diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index dcc01786d2f..5a3ff51f0e5 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -340,7 +340,22 @@ ValueTask ReadImpl(DreamDaemonSettings settings, CancellationToke result.CurrentAllowWebclient = llp?.AllowWebClient.Value; result.Port = settings.Port.Value; result.AllowWebClient = settings.AllowWebClient.Value; - result.Status = dd.Status; + + var firstIteration = true; + do + { + if (!firstIteration) + { + cancellationToken.ThrowIfCancellationRequested(); + await Task.Yield(); + } + + firstIteration = false; + result.Status = dd.Status; + result.SessionId = dd.SessionId; + } + while (result.Status == WatchdogStatus.Online && !result.SessionId.HasValue); // this is the one invalid combo, it's not that racy + result.SecurityLevel = settings.SecurityLevel.Value; result.Visibility = settings.Visibility.Value; result.SoftRestart = rstate == RebootState.Restart; diff --git a/src/Tgstation.Server.Host/Models/ReattachInformation.cs b/src/Tgstation.Server.Host/Models/ReattachInformation.cs index 00409df99a9..d4d1520d08c 100644 --- a/src/Tgstation.Server.Host/Models/ReattachInformation.cs +++ b/src/Tgstation.Server.Host/Models/ReattachInformation.cs @@ -7,11 +7,6 @@ namespace Tgstation.Server.Host.Models ///
public sealed class ReattachInformation : ReattachInformationBase { - /// - /// The row Id. - /// - public long Id { get; set; } - /// /// The for the . /// diff --git a/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs b/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs index 241fae5141a..b233f0c0179 100644 --- a/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs +++ b/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs @@ -1,5 +1,4 @@ using System; -using System.Globalization; using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Components.Interop; @@ -12,6 +11,11 @@ namespace Tgstation.Server.Host.Models ///
public abstract class ReattachInformationBase : DMApiParameters { + /// + /// The database row Id. + /// + public long? Id { get; set; } + /// /// The system process ID. /// @@ -51,6 +55,7 @@ protected ReattachInformationBase() protected ReattachInformationBase(ReattachInformationBase copy) { ArgumentNullException.ThrowIfNull(copy); + Id = copy.Id; AccessIdentifier = copy.AccessIdentifier; Port = copy.Port; ProcessId = copy.ProcessId; @@ -60,6 +65,6 @@ protected ReattachInformationBase(ReattachInformationBase copy) } /// - public override string ToString() => String.Format(CultureInfo.InvariantCulture, "Process ID: {0}, Access Identifier {1}, RebootState: {2}, Port: {3}", ProcessId, AccessIdentifier, RebootState, Port); + public override string ToString() => $"Session: {Id}, PID: {ProcessId}, Access Identifier {AccessIdentifier}, RebootState: {RebootState}, Port: {Port}"; } } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 756712f0a97..dc45068fd32 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -1,4 +1,4 @@ -using Byond.TopicSender; +using Byond.TopicSender; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.Logging; @@ -68,11 +68,11 @@ sealed class WatchdogTest : JobsRequiredTest readonly bool highPrioDD; readonly TopicClient topicClient; readonly EngineVersion testVersion; - readonly bool usingBasicWatchdog; + readonly bool watchdogRestartsProcess; bool ranTimeoutTest = false; - public WatchdogTest(EngineVersion testVersion, IInstanceClient instanceClient, InstanceManager instanceManager, ushort serverPort, bool highPrioDD, ushort ddPort, bool usingBasicWatchdog) + public WatchdogTest(EngineVersion testVersion, IInstanceClient instanceClient, InstanceManager instanceManager, ushort serverPort, bool highPrioDD, ushort ddPort, bool watchdogRestartsProcess) : base(instanceClient.Jobs) { this.instanceClient = instanceClient ?? throw new ArgumentNullException(nameof(instanceClient)); @@ -81,7 +81,7 @@ public WatchdogTest(EngineVersion testVersion, IInstanceClient instanceClient, I this.highPrioDD = highPrioDD; this.ddPort = ddPort; this.testVersion = testVersion ?? throw new ArgumentNullException(nameof(testVersion)); - this.usingBasicWatchdog = usingBasicWatchdog; + this.watchdogRestartsProcess = watchdogRestartsProcess || testVersion.Engine.Value == EngineType.OpenDream; topicClient = new(new SocketParameters { @@ -194,6 +194,7 @@ async ValueTask RunTest(bool useTrusted) { SoftShutdown = true, }, cancellationToken); + ValidateSessionId(currentStatus, true); Assert.AreEqual(WatchdogStatus.Online, currentStatus.Status); @@ -221,7 +222,7 @@ async ValueTask RunTest(bool useTrusted) await RunTest(true); - if (new PlatformIdentifier().IsWindows || !usingBasicWatchdog) + if (new PlatformIdentifier().IsWindows || !watchdogRestartsProcess) await RunTest(false); } @@ -301,12 +302,15 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) Assert.AreEqual(WatchdogStatus.Online, currentStatus.Status); Assert.IsNotNull(currentStatus.StagedCompileJob); + ValidateSessionId(currentStatus, false); var expectedStaged = currentStatus.StagedCompileJob; Assert.AreNotEqual(expectedStaged.Id, currentStatus.ActiveCompileJob.Id); - await TellWorldToReboot(false, cancellationToken); + Assert.AreEqual(watchdogRestartsProcess, currentStatus.SoftRestart); + Assert.IsFalse(currentStatus.SoftShutdown.Value); - currentStatus = await instanceClient.DreamDaemon.Read(cancellationToken); + currentStatus = await TellWorldToReboot(true, cancellationToken); + ValidateSessionId(currentStatus, watchdogRestartsProcess); Assert.AreEqual(expectedStaged.Id, currentStatus.ActiveCompileJob.Id); await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken); @@ -320,9 +324,8 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) Assert.IsNotNull(topicRequestResult); Assert.AreEqual("we love casting spells", topicRequestResult.StringData); - await DeployTestDme("LongRunning/long_running_test", DreamDaemonSecurity.Trusted, true, cancellationToken); - - currentStatus = await instanceClient.DreamDaemon.Read(cancellationToken); + currentStatus = await DeployTestDme("LongRunning/long_running_test", DreamDaemonSecurity.Trusted, true, cancellationToken); + ValidateSessionId(currentStatus, false); Assert.AreEqual(WatchdogStatus.Online, currentStatus.Status); Assert.IsNotNull(currentStatus.StagedCompileJob); @@ -330,8 +333,9 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) expectedStaged = currentStatus.StagedCompileJob; Assert.AreNotEqual(expectedStaged.Id, currentStatus.ActiveCompileJob.Id); - currentStatus = await TellWorldToReboot(false, cancellationToken); + currentStatus = await TellWorldToReboot(true, cancellationToken); + ValidateSessionId(currentStatus, watchdogRestartsProcess); Assert.AreEqual(WatchdogStatus.Online, currentStatus.Status); Assert.IsNull(currentStatus.StagedCompileJob); Assert.AreEqual(expectedStaged.Id, currentStatus.ActiveCompileJob.Id); @@ -513,6 +517,7 @@ async Task DumpTests(CancellationToken cancellationToken) await Task.Delay(TimeSpan.FromSeconds(20), cancellationToken); var ddStatus = await instanceClient.DreamDaemon.Read(cancellationToken); + ValidateSessionId(ddStatus, true); Assert.AreEqual(WatchdogStatus.Online, ddStatus.Status.Value); } @@ -534,6 +539,7 @@ async Task TestDMApiFreeDeploy(CancellationToken cancellationToken) daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value); + ValidateSessionId(daemonStatus, true); CheckDDPriority(); Assert.AreEqual(false, daemonStatus.SoftRestart); Assert.AreEqual(false, daemonStatus.SoftShutdown); @@ -568,6 +574,7 @@ async Task RunBasicTest(CancellationToken cancellationToken) Assert.AreEqual(WatchdogStatus.Offline, daemonStatus.Status.Value); Assert.IsNotNull(daemonStatus.ActiveCompileJob); + Assert.IsFalse(daemonStatus.SessionId.HasValue); Assert.IsNull(daemonStatus.StagedCompileJob); Assert.AreEqual(DMApiConstants.InteropVersion, daemonStatus.ActiveCompileJob.DMApiVersion); Assert.AreEqual(DreamDaemonSecurity.Trusted, daemonStatus.ActiveCompileJob.MinimumSecurityLevel); @@ -602,6 +609,7 @@ async Task RunBasicTest(CancellationToken cancellationToken) daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value); + ValidateSessionId(daemonStatus, true); CheckDDPriority(); Assert.AreEqual(false, daemonStatus.SoftRestart); Assert.AreEqual(false, daemonStatus.SoftShutdown); @@ -610,6 +618,7 @@ async Task RunBasicTest(CancellationToken cancellationToken) daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.AreEqual(WatchdogStatus.Offline, daemonStatus.Status.Value); + Assert.IsFalse(daemonStatus.SessionId.HasValue); await CheckDMApiFail(daemonStatus.ActiveCompileJob, cancellationToken, false); @@ -619,11 +628,29 @@ async Task RunBasicTest(CancellationToken cancellationToken) LogOutput = true, }, cancellationToken); Assert.AreEqual(string.Empty, daemonStatus.AdditionalParameters); + Assert.IsFalse(daemonStatus.SessionId.HasValue); + } + + long? sessionIdTracker; + void ValidateSessionId(DreamDaemonResponse daemonStatus, bool? knownIncrease) + { + Assert.IsTrue(daemonStatus.SessionId.HasValue, $"Expected a session ID in the DreamDaemonResponse"); + + if (sessionIdTracker.HasValue) + if (knownIncrease.HasValue) + if (knownIncrease.Value) + Assert.IsTrue(daemonStatus.SessionId.Value > sessionIdTracker.Value, $"Expected a session ID > {sessionIdTracker.Value}, got {daemonStatus.SessionId.Value} instead"); + else + Assert.AreEqual(sessionIdTracker.Value, daemonStatus.SessionId.Value); + else + Assert.IsTrue(daemonStatus.SessionId.Value >= sessionIdTracker.Value, $"Expected a session ID >= {sessionIdTracker.Value}, got {daemonStatus.SessionId.Value} instead"); + + sessionIdTracker = daemonStatus.SessionId.Value; } void TestLinuxIsntBeingFuckingCheekyAboutFilePaths(DreamDaemonResponse currentStatus, CompileJobResponse previousStatus) { - if (new PlatformIdentifier().IsWindows || usingBasicWatchdog || currentStatus.ActiveCompileJob.EngineVersion.Engine.Value == EngineType.OpenDream) + if (new PlatformIdentifier().IsWindows || watchdogRestartsProcess) return; Assert.IsNotNull(currentStatus.ActiveCompileJob); @@ -721,17 +748,17 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke Assert.IsNotNull(topicRequestResult.StringData); Assert.AreEqual(topicRequestResult.StringData, "received health check"); - await instanceClient.DreamDaemon.Update(new DreamDaemonRequest + var ddStatus = await instanceClient.DreamDaemon.Update(new DreamDaemonRequest { SoftShutdown = true }, cancellationToken); + ValidateSessionId(ddStatus, true); ourProcessHandler.Suspend(); await Task.WhenAny(ourProcessHandler.Lifetime, Task.Delay(TimeSpan.FromMinutes(1), cancellationToken)); var timeout = 60; - DreamDaemonResponse ddStatus; do { await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); @@ -1083,6 +1110,7 @@ async Task RunLongRunningTestThenUpdate(CancellationToken cancellationToken) daemonStatus = await DeployTestDme(DmeName, DreamDaemonSecurity.Safe, true, cancellationToken); Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value); + ValidateSessionId(daemonStatus, true); CheckDDPriority(); Assert.AreEqual(initialCompileJob.Id, daemonStatus.ActiveCompileJob.Id); @@ -1093,8 +1121,9 @@ async Task RunLongRunningTestThenUpdate(CancellationToken cancellationToken) Assert.AreEqual(DreamDaemonSecurity.Safe, newerCompileJob.MinimumSecurityLevel); await CheckDMApiFail(daemonStatus.ActiveCompileJob, cancellationToken); - daemonStatus = await TellWorldToReboot(false, cancellationToken); + daemonStatus = await TellWorldToReboot(true, cancellationToken); + ValidateSessionId(daemonStatus, watchdogRestartsProcess); Assert.AreNotEqual(initialCompileJob.Id, daemonStatus.ActiveCompileJob.Id); Assert.IsNull(daemonStatus.StagedCompileJob); @@ -1126,7 +1155,7 @@ async Task RunLongRunningTestThenUpdateWithNewDme(CancellationToken cancellation daemonStatus = await DeployTestDme("LongRunning/long_running_test_copy", DreamDaemonSecurity.Safe, true, cancellationToken); - + ValidateSessionId(daemonStatus, true); Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value); CheckDDPriority(); @@ -1140,6 +1169,7 @@ async Task RunLongRunningTestThenUpdateWithNewDme(CancellationToken cancellation await CheckDMApiFail(daemonStatus.ActiveCompileJob, cancellationToken); daemonStatus = await TellWorldToReboot(true, cancellationToken); + ValidateSessionId(daemonStatus, true); // remember, dme name change triggers reboot Assert.AreNotEqual(initialCompileJob.Id, daemonStatus.ActiveCompileJob.Id); Assert.IsNull(daemonStatus.StagedCompileJob); @@ -1191,7 +1221,7 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken var daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value); Assert.IsNotNull(daemonStatus.ActiveCompileJob); - + ValidateSessionId(daemonStatus, true); Assert.AreEqual(initialStatus.ActiveCompileJob.Id, daemonStatus.ActiveCompileJob.Id); var newerCompileJob = daemonStatus.StagedCompileJob; @@ -1206,6 +1236,7 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken Assert.AreEqual(versionToInstall, daemonStatus.ActiveCompileJob.EngineVersion); Assert.IsNull(daemonStatus.StagedCompileJob); + ValidateSessionId(daemonStatus, true); await instanceClient.DreamDaemon.Shutdown(cancellationToken); await CheckDMApiFail(daemonStatus.ActiveCompileJob, cancellationToken); @@ -1217,9 +1248,7 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken public async Task StartAndLeaveRunning(CancellationToken cancellationToken) { System.Console.WriteLine("TEST: WATCHDOG STARTING ENDLESS"); - var dd = await instanceClient.DreamDaemon.Read(cancellationToken); - if (dd.ActiveCompileJob == null) - await DeployTestDme("LongRunning/long_running_test", DreamDaemonSecurity.Trusted, true, cancellationToken); + await DeployTestDme("LongRunning/long_running_test", DreamDaemonSecurity.Trusted, true, cancellationToken); var startJob = await StartDD(cancellationToken); @@ -1235,6 +1264,7 @@ public async Task StartAndLeaveRunning(CancellationToken cancellationToken) bool firstTime = true; do { + ValidateSessionId(daemonStatus, true); KillDD(firstTime); firstTime = false; await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); @@ -1255,6 +1285,7 @@ public async Task StartAndLeaveRunning(CancellationToken cancellationToken) await Task.Delay(TimeSpan.FromSeconds(15), cancellationToken); daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); + ValidateSessionId(daemonStatus, true); Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value); await CheckDMApiFail(daemonStatus.ActiveCompileJob, cancellationToken); } @@ -1272,9 +1303,9 @@ bool KillDD(bool require) return ddProc != null; } - public Task TellWorldToReboot(bool allowRestoring, CancellationToken cancellationToken) - => TellWorldToReboot2(instanceClient, topicClient, FindTopicPort(), allowRestoring ? true : testVersion.Engine.Value == EngineType.OpenDream, cancellationToken); - public static async Task TellWorldToReboot2(IInstanceClient instanceClient, ITopicClient topicClient, ushort topicPort, bool allowRestoring, CancellationToken cancellationToken) + public Task TellWorldToReboot(bool waitForOnlineIfRestoring, CancellationToken cancellationToken) + => TellWorldToReboot2(instanceClient, topicClient, FindTopicPort(), waitForOnlineIfRestoring ? true : testVersion.Engine.Value == EngineType.OpenDream, cancellationToken); + public static async Task TellWorldToReboot2(IInstanceClient instanceClient, ITopicClient topicClient, ushort topicPort, bool waitForOnlineIfRestoring, CancellationToken cancellationToken) { var daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.IsNotNull(daemonStatus.StagedCompileJob); @@ -1301,7 +1332,7 @@ public static async Task TellWorldToReboot2(IInstanceClient await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken); - if (allowRestoring && daemonStatus.Status == WatchdogStatus.Restoring) + if (waitForOnlineIfRestoring && daemonStatus.Status == WatchdogStatus.Restoring) { do { diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index e44020cf716..2c65616d4af 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -29,7 +29,6 @@ using Tgstation.Server.Api; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Api.Rights; @@ -1324,7 +1323,7 @@ async Task TestTgsInternal(CancellationToken hardCancellationToken) try { Api.Models.Instance instance; - long initialStaged, initialActive; + long initialStaged, initialActive, initialSessionId; await using var firstAdminClient = await CreateAdminClient(server.ApiUrl, cancellationToken); async ValueTask CreateUserWithNoInstancePerms() @@ -1403,6 +1402,7 @@ async Task FailFast(Task task) async Task RunInstanceTests() { + var testSerialized = TestingUtils.RunningInGitHubActions; // they only have 2 cores, can't handle intense parallelization async Task ODCompatTests() { var edgeODVersionTask = EngineTest.GetEdgeVersion(EngineType.OpenDream, fileDownloader, cancellationToken); @@ -1433,7 +1433,7 @@ await instanceTest var odCompatTests = FailFast(ODCompatTests()); - if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization + if (testSerialized) // they only have 2 cores, can't handle intense parallelization await odCompatTests; var compatTests = FailFast( @@ -1453,7 +1453,7 @@ await instanceTest server.UsingBasicWatchdog, cancellationToken)); - if (TestingUtils.RunningInGitHubActions) // they only have 2 cores, can't handle intense parallelization + if (testSerialized) await compatTests; await FailFast( @@ -1481,6 +1481,7 @@ await FailFast( Assert.AreNotEqual(dd.StagedCompileJob.Id, dd.ActiveCompileJob.Id); initialActive = dd.ActiveCompileJob.Id.Value; initialStaged = dd.StagedCompileJob.Id.Value; + initialSessionId = dd.SessionId.Value; jobsHubTest.ExpectShutdown(); await firstAdminClient.Administration.Restart(cancellationToken); @@ -1562,6 +1563,7 @@ await FailFast( Assert.AreNotEqual(dd.StagedCompileJob.Id, dd.ActiveCompileJob.Id); Assert.AreEqual(initialStaged, dd.StagedCompileJob.Id); Assert.AreEqual(initialActive, dd.ActiveCompileJob.Id); + Assert.AreEqual(initialSessionId, dd.SessionId); var chatReadTask = instanceClient.ChatBots.List(null, cancellationToken); From 34ddb2f72504725f21208e66f79277f6ba5bed8d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 19 Nov 2023 17:11:26 -0500 Subject: [PATCH 193/717] Do not duplicate logging here --- .../Components/Watchdog/AdvancedWatchdog.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs index afc801476eb..259dd743407 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs @@ -242,8 +242,7 @@ protected sealed override async ValueTask HandleNewDmbAvailable(CancellationToke ActiveCompileJob.EngineVersion); canSeamlesslySwap = false; } - - if (compileJobProvider.CompileJob.DmeName != ActiveCompileJob.DmeName) + else if (compileJobProvider.CompileJob.DmeName != ActiveCompileJob.DmeName) { Logger.LogDebug( "Not swapping to new compile job {0} as it uses a different .dmb name ({1}) than what is currently active {2}. Queueing graceful restart instead...", From b01700ec6cfd662e3a2000b22da560b896076790 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 19 Nov 2023 17:11:44 -0500 Subject: [PATCH 194/717] Log sleep_offline with Export and Topic --- tests/DMAPI/LongRunning/Test.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/DMAPI/LongRunning/Test.dm b/tests/DMAPI/LongRunning/Test.dm index 2ee16cc2de1..d833eb7aba8 100644 --- a/tests/DMAPI/LongRunning/Test.dm +++ b/tests/DMAPI/LongRunning/Test.dm @@ -98,11 +98,11 @@ /world/Topic(T, Addr, Master, Keys) if(findtext(T, "tgs_integration_test_tactics3") == 0) - log << "Topic: [T]" + log << "Topic (sleep_offline: [sleep_offline]): [T]" else log << "tgs_integration_test_tactics3 " . = HandleTopic(T) - log << "Response: [.]" + log << "Response (sleep_offline: [sleep_offline]): [.]" var/startup_complete var/run_bridge_test @@ -246,9 +246,9 @@ var/received_health_check = FALSE /world/Export(url) var/redact = length(url) > 1000 - log << "Export: [redact ? "" : url]" + log << "Export (sleep_offline: [sleep_offline]): [redact ? "" : url]" . = ..() - log << "Export completed: [redact ? "" : json_encode(.)]" + log << "Export completed (sleep_offline: [sleep_offline]): [redact ? "" : json_encode(.)]" /proc/RebootAsync() set waitfor = FALSE From 84c5359af74fdedd9cbc2c3a3d9dce4ed0e36fdc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 19 Nov 2023 19:37:02 -0500 Subject: [PATCH 195/717] Fix basic watchdog tests --- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index a512f97a687..764814e4954 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1280,8 +1280,8 @@ async Task TestTgsInternal(CancellationToken hardCancellationToken) // uncomment to force this test to run with DummyChatProviders // missingChatVarsCount = TotalChatVars; - // uncomment to force this test to run with pasic watchdog - // Environment.SetEnvironmentVariable("General__UseBasicWatchdog", "true"); + // uncomment to force this test to run with basic watchdog + Environment.SetEnvironmentVariable("General__UseBasicWatchdog", "true"); if (missingChatVarsCount != 0) { @@ -1586,7 +1586,7 @@ await FailFast( Assert.AreEqual(connectedChannelCount, topicRequestResult.FloatData.Value); - dd = await WatchdogTest.TellWorldToReboot2(instanceClient, WatchdogTest.StaticTopicClient, mainDDPort, false, cancellationToken); + dd = await WatchdogTest.TellWorldToReboot2(instanceClient, WatchdogTest.StaticTopicClient, mainDDPort, true, cancellationToken); Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value); // if this assert fails, you likely have to crack open the debugger and read test_fail_reason.txt manually Assert.IsNull(dd.StagedCompileJob); @@ -1655,7 +1655,7 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) Assert.AreEqual(dd.StagedCompileJob.Job.Id, compileJob.Id); expectedCompileJobId = compileJob.Id.Value; - dd = await wdt.TellWorldToReboot(false, cancellationToken); + dd = await wdt.TellWorldToReboot(server.UsingBasicWatchdog, cancellationToken); Assert.AreEqual(dd.ActiveCompileJob.Job.Id, expectedCompileJobId); Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value); From ac545ebcfb93ecb54da679006c4b9b553671eb5e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 20 Nov 2023 15:09:36 -0500 Subject: [PATCH 196/717] Fix CI blunder --- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 764814e4954..9a00b98d5b5 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1281,7 +1281,7 @@ async Task TestTgsInternal(CancellationToken hardCancellationToken) // missingChatVarsCount = TotalChatVars; // uncomment to force this test to run with basic watchdog - Environment.SetEnvironmentVariable("General__UseBasicWatchdog", "true"); + // Environment.SetEnvironmentVariable("General__UseBasicWatchdog", "true"); if (missingChatVarsCount != 0) { From c3856fcec1a44c26d7a17125ff58b572889339b0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 19 Nov 2023 23:46:24 -0500 Subject: [PATCH 197/717] Create a live test OpenDream can use in their CI Clean up other minor test things --- .github/CONTRIBUTING.md | 3 + .../Live/Instance/EngineTest.cs | 24 ++++-- .../Live/Instance/InstanceTest.cs | 30 ++++--- .../Live/Instance/WatchdogTest.cs | 3 - .../Live/LiveTestingServer.cs | 9 ++ .../Live/TestLiveServer.cs | 84 +++++++++++++------ tests/Tgstation.Server.Tests/TestingUtils.cs | 4 +- 7 files changed, 111 insertions(+), 46 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b8709f641fd..0dee22f9b4b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -51,6 +51,9 @@ In order to run the integration tests you must have the following environment va - `TGS_TEST_DISCORD_CHANNEL`: To a valid discord channel ID that the above bot can access. - `TGS_TEST_IRC_CONNECTION_STRING`: To a valid IRC connection string. See the code for [IrcConnectionStringBuilder](../src/Tgstation.Server.Api/Models/IrcConnectionStringBuilder.cs) for details. - `TGS_TEST_IRC_CHANNEL`: To a valid IRC channel accessible with the above connection. +- (Optional) `TGS_TEST_OD_ENGINE_VERSION`: Specify the full git commit SHA of the [OpenDream](https://github.com/OpenDreamProject/OpenDream) version to use in the main integration test, the default is the current HEAD of the default branch. +- (Optional) `TGS_TEST_OD_GIT_DIRECTORY`: Path to a local [OpenDream](https://github.com/OpenDreamProject/OpenDream) git repository to use as an upstream for testing. +- (Optional) `TGS_TEST_OD_EXCLUSIVE`: Set to `true` to enable the quicker integration test that only runs [OpenDream](https://github.com/OpenDreamProject/OpenDream) functionality. This is tested by default in the main integration test. ### Notes About Forks diff --git a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs index b90d054ef81..83e7f322c9b 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs @@ -82,13 +82,25 @@ public static async ValueTask GetEdgeVersion(EngineType engineTyp } else if (engineType == EngineType.OpenDream) { - var masterBranch = await TestingGitHubService.RealTestClient.Repository.Branch.Get("OpenDreamProject", "OpenDream", "master"); - - engineVersion = new EngineVersion + var forcedVersion = Environment.GetEnvironmentVariable("TGS_TEST_OD_ENGINE_VERSION"); + if (!String.IsNullOrWhiteSpace(forcedVersion)) + { + engineVersion = new EngineVersion + { + Engine = EngineType.OpenDream, + SourceSHA = forcedVersion, + }; + } + else { - Engine = EngineType.OpenDream, - SourceSHA = masterBranch.Commit.Sha, - }; + var masterBranch = await TestingGitHubService.RealTestClient.Repository.Branch.Get("OpenDreamProject", "OpenDream", "master"); + + engineVersion = new EngineVersion + { + Engine = EngineType.OpenDream, + SourceSHA = masterBranch.Commit.Sha, + }; + } } else { diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 21a54ebce8e..255a2e8a83a 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -23,6 +23,7 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.System; namespace Tgstation.Server.Tests.Live.Instance @@ -78,15 +79,23 @@ public async Task RunTests( public static async ValueTask DownloadEngineVersion( EngineVersion compatVersion, - IInstanceClient instanceClient, IFileDownloader fileDownloader, + Uri openDreamUrl, CancellationToken cancellationToken) { - var odRepoDir = Path.GetFullPath(Path.Combine(instanceClient.Metadata.Path, "..", "OpenDreamRepo")); - var tmpIOManager = new ResolvingIOManager(new DefaultIOManager(), odRepoDir); + var ioManager = new DefaultIOManager(); + var odRepoDir = ioManager.ConcatPath( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + new AssemblyInformationProvider().VersionPrefix, + "OpenDreamRepository"); + var odRepoIoManager = new ResolvingIOManager(ioManager, odRepoDir); var mockOptions = new Mock>(); - mockOptions.SetupGet(x => x.Value).Returns(new GeneralConfiguration()); + var genConfig = new GeneralConfiguration + { + OpenDreamGitUrl = openDreamUrl, + }; + mockOptions.SetupGet(x => x.Value).Returns(genConfig); IEngineInstaller byondInstaller = compatVersion.Engine == EngineType.OpenDream ? new OpenDreamInstaller( @@ -98,20 +107,20 @@ public static async ValueTask DownloadEngineVersion( new LibGit2RepositoryFactory( Mock.Of>()), new LibGit2Commands(), - tmpIOManager, + odRepoIoManager, new NoopEventConsumer(), Mock.Of(), Mock.Of(), Mock.Of>(), Mock.Of>(), - new GeneralConfiguration()), + genConfig), mockOptions.Object) : new PlatformIdentifier().IsWindows ? new WindowsByondInstaller( Mock.Of(), Mock.Of(), fileDownloader, - Options.Create(new GeneralConfiguration()), + Options.Create(genConfig), Mock.Of>()) : new PosixByondInstaller( Mock.Of(), @@ -127,6 +136,7 @@ public static async ValueTask DownloadEngineVersion( public async Task RunCompatTests( EngineVersion compatVersion, + Uri openDreamUrl, IInstanceClient instanceClient, ushort dmPort, ushort ddPort, @@ -191,7 +201,7 @@ public async Task RunCompatTests( EngineInstallResponse installJob2; await using (var stableBytesMs = await TestingUtils.ExtractMemoryStreamFromInstallationData( - await DownloadEngineVersion(compatVersion, instanceClient, fileDownloader, cancellationToken), + await DownloadEngineVersion(compatVersion, fileDownloader, openDreamUrl, cancellationToken), cancellationToken)) { installJob2 = await instanceClient.Engine.SetActiveVersion(new EngineVersionRequest @@ -235,9 +245,7 @@ await Task.WhenAll( var configSetupTask = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata).SetupDMApiTests(true, cancellationToken); - if (TestingUtils.RunningInGitHubActions - || String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN")) - || Environment.MachineName.Equals("CYBERSTATIONXVI", StringComparison.OrdinalIgnoreCase)) + if (!String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"))) await instanceClient.Repository.Update(new RepositoryUpdateRequest { CreateGitHubDeployments = true, diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index d140973d83b..bcde5714ff2 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -20,7 +20,6 @@ using System.Net.Sockets; using System.Reflection; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics.Arm; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -41,8 +40,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -using static NuGet.Frameworks.FrameworkConstants; - namespace Tgstation.Server.Tests.Live.Instance { sealed class WatchdogTest : JobsRequiredTest diff --git a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs index aed4357b727..6fce2c452c9 100644 --- a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs +++ b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs @@ -56,6 +56,8 @@ static async Task Cleanup(string directory) public Uri RootUrl { get; } + public Uri OpenDreamUrl { get; } + public string Directory { get; } public string UpdatePath { get; } @@ -123,6 +125,12 @@ public LiveTestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth HighPriorityDreamDaemon = nicingAllowed; LowPriorityDeployments = nicingAllowed; + var odGitDir = Environment.GetEnvironmentVariable("TGS_TEST_OD_GIT_DIRECTORY"); + if (!String.IsNullOrWhiteSpace(odGitDir)) + OpenDreamUrl = new Uri($"file://{Path.GetFullPath(odGitDir).Replace('\\', '/')}"); + else + OpenDreamUrl = new GeneralConfiguration().OpenDreamGitUrl; + args = new List() { String.Format(CultureInfo.InvariantCulture, "Database:DropDatabase={0}", true), // Replaced after first Run @@ -144,6 +152,7 @@ public LiveTestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth $"Session:HighPriorityLiveDreamDaemon={HighPriorityDreamDaemon}", $"Session:LowPriorityDeploymentProcesses={LowPriorityDeployments}", $"General:SkipAddingByondFirewallException={!TestingUtils.RunningInGitHubActions}", + $"General:OpenDreamGitUrl={OpenDreamUrl}", }; swarmArgs = new List(); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 9a00b98d5b5..14b26d8ec85 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1208,7 +1208,18 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest } [TestMethod] - public async Task TestStandardTgsOperation() + public Task TestStandardTgsOperation() => TestStandardTgsOperation(false); + + [TestMethod] + public Task TestOpenDreamExclusiveTgsOperation() + { + if (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS_TEST_OD_EXCLUSIVE"))) + Assert.Inconclusive("This test is covered by TestStandardTgsOperation"); + + return TestStandardTgsOperation(true); + } + + async Task TestStandardTgsOperation(bool openDreamOnly) { using(var currentProcess = System.Diagnostics.Process.GetCurrentProcess()) { @@ -1233,7 +1244,7 @@ public async Task TestStandardTgsOperation() ServiceCollectionExtensions.UseAdditionalLoggerProvider(); var failureTask = HardFailLoggerProvider.FailureSource; - var internalTask = TestTgsInternal(hardCancellationToken); + var internalTask = TestTgsInternal(openDreamOnly, hardCancellationToken); await Task.WhenAny( internalTask, failureTask); @@ -1266,7 +1277,7 @@ await Task.WhenAny( await internalTask; } - async Task TestTgsInternal(CancellationToken hardCancellationToken) + async Task TestTgsInternal(bool openDreamOnly, CancellationToken hardCancellationToken) { var discordConnectionString = Environment.GetEnvironmentVariable("TGS_TEST_DISCORD_TOKEN"); var ircConnectionString = Environment.GetEnvironmentVariable("TGS_TEST_IRC_CONNECTION_STRING"); @@ -1379,24 +1390,41 @@ async Task FailFast(Task task) } } - var rootTest = FailFast(RawRequestTests.Run(clientFactory, firstAdminClient, cancellationToken)); - var adminTest = FailFast(new AdministrationTest(firstAdminClient.Administration).Run(cancellationToken)); - var usersTest = FailFast(new UsersTest(firstAdminClient).Run(cancellationToken)); - - jobsHubTestTask = FailFast(jobsHubTest.Run(cancellationToken)); - var instanceManagerTest = new InstanceManagerTest(firstAdminClient, server.Directory); - var compatInstanceTask = instanceManagerTest.CreateTestInstance("CompatTestsInstance", cancellationToken); - var odInstanceTask = instanceManagerTest.CreateTestInstance("OdTestsInstance", cancellationToken); - var byondApiCompatInstanceTask = instanceManagerTest.CreateTestInstance("BCAPITestsInstance", cancellationToken); - instance = await instanceManagerTest.CreateTestInstance("LiveTestsInstance", cancellationToken); - var compatInstance = await compatInstanceTask; - var odInstance = await odInstanceTask; - var byondApiCompatInstance = await byondApiCompatInstanceTask; - var instancesTest = FailFast(instanceManagerTest.RunPreTest(cancellationToken)); - Assert.IsTrue(Directory.Exists(instance.Path)); - var instanceClient = firstAdminClient.Instances.CreateClient(instance); - - Assert.IsTrue(Directory.Exists(instanceClient.Metadata.Path)); + Task nonInstanceTests; + IInstanceClient instanceClient = null; + InstanceResponse odInstance, compatInstance; + if (!openDreamOnly) + { + var rootTest = FailFast(RawRequestTests.Run(clientFactory, firstAdminClient, cancellationToken)); + var adminTest = FailFast(new AdministrationTest(firstAdminClient.Administration).Run(cancellationToken)); + var usersTest = FailFast(new UsersTest(firstAdminClient).Run(cancellationToken)); + + jobsHubTestTask = FailFast(jobsHubTest.Run(cancellationToken)); + var instanceManagerTest = new InstanceManagerTest(firstAdminClient, server.Directory); + var compatInstanceTask = instanceManagerTest.CreateTestInstance("CompatTestsInstance", cancellationToken); + var odInstanceTask = instanceManagerTest.CreateTestInstance("OdTestsInstance", cancellationToken); + var byondApiCompatInstanceTask = instanceManagerTest.CreateTestInstance("BCAPITestsInstance", cancellationToken); + instance = await instanceManagerTest.CreateTestInstance("LiveTestsInstance", cancellationToken); + compatInstance = await compatInstanceTask; + odInstance = await odInstanceTask; + var byondApiCompatInstance = await byondApiCompatInstanceTask; + var instancesTest = FailFast(instanceManagerTest.RunPreTest(cancellationToken)); + Assert.IsTrue(Directory.Exists(instance.Path)); + instanceClient = firstAdminClient.Instances.CreateClient(instance); + + Assert.IsTrue(Directory.Exists(instanceClient.Metadata.Path)); + nonInstanceTests = Task.WhenAll(instancesTest, adminTest, rootTest, usersTest); + } + else + { + compatInstance = null; + nonInstanceTests = Task.CompletedTask; + jobsHubTestTask = null; + instance = null; + var instanceManagerTest = new InstanceManagerTest(firstAdminClient, server.Directory); + var odInstanceTask = instanceManagerTest.CreateTestInstance("OdTestsInstance", cancellationToken); + odInstance = await odInstanceTask; + } var instanceTest = new InstanceTest( firstAdminClient.Instances, @@ -1418,8 +1446,8 @@ async Task ODCompatTests() Engine = EngineType.OpenDream, SourceSHA = "f1dc153caf9d84cd1d0056e52286cc0163e3f4d3", // 1b4 verified version }, - instanceClient, fileDownloader, + server.OpenDreamUrl, cancellationToken).AsTask()); Assert.AreEqual(ErrorCode.OpenDreamTooOld, ex.ErrorCode); @@ -1427,6 +1455,7 @@ async Task ODCompatTests() await instanceTest .RunCompatTests( await edgeODVersionTask, + server.OpenDreamUrl, firstAdminClient.Instances.CreateClient(odInstance), odDMPort, odDDPort, @@ -1437,9 +1466,12 @@ await instanceTest var odCompatTests = FailFast(ODCompatTests()); - if (testSerialized) // they only have 2 cores, can't handle intense parallelization + if (openDreamOnly || testSerialized) await odCompatTests; + if (openDreamOnly) + return; + var compatTests = FailFast( instanceTest .RunCompatTests( @@ -1450,6 +1482,7 @@ await instanceTest ? new Version(510, 1346) : new Version(512, 1451) // http://www.byond.com/forum/?forum=5&command=search&scope=local&text=resolved%3a512.1451 }, + server.OpenDreamUrl, firstAdminClient.Instances.CreateClient(compatInstance), compatDMPort, compatDDPort, @@ -1477,7 +1510,10 @@ await FailFast( var instanceTests = RunInstanceTests(); - await Task.WhenAll(rootTest, adminTest, instancesTest, instanceTests, usersTest); + await Task.WhenAll(nonInstanceTests, instanceTests); + + if (openDreamOnly) + return; var dd = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value); diff --git a/tests/Tgstation.Server.Tests/TestingUtils.cs b/tests/Tgstation.Server.Tests/TestingUtils.cs index b40e940e398..3167d2c3d3f 100644 --- a/tests/Tgstation.Server.Tests/TestingUtils.cs +++ b/tests/Tgstation.Server.Tests/TestingUtils.cs @@ -38,12 +38,12 @@ public static async ValueTask ExtractMemoryStreamFromInstallationData(IE if (engineInstallationData is ZipStreamEngineInstallationData zipStreamData) return (MemoryStream)zipStreamData.GetType().GetField("zipStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(zipStreamData); - await using var repoData = (RepositoryEngineInstallationData)engineInstallationData; + await using var grabby = engineInstallationData; var tempFolder = Path.GetTempFileName(); File.Delete(tempFolder); try { - await repoData.ExtractToPath(tempFolder, cancellationToken); + await engineInstallationData.ExtractToPath(tempFolder, cancellationToken); var resultStream = new FileStream( $"{tempFolder}.zip", FileMode.Create, From 042116506bae7eb4835e5a98f916fe179f34a342 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 16:38:41 -0500 Subject: [PATCH 198/717] Fix the `AutoGeneratedProgram.Main` warning --- build/TestCommon.props | 2 +- .../Tgstation.Server.Host.Tests.Signals.csproj | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/build/TestCommon.props b/build/TestCommon.props index 234e06735a4..b68ecb34159 100644 --- a/build/TestCommon.props +++ b/build/TestCommon.props @@ -13,7 +13,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/tests/Tgstation.Server.Host.Tests.Signals/Tgstation.Server.Host.Tests.Signals.csproj b/tests/Tgstation.Server.Host.Tests.Signals/Tgstation.Server.Host.Tests.Signals.csproj index 7755d969458..c098cb04d35 100644 --- a/tests/Tgstation.Server.Host.Tests.Signals/Tgstation.Server.Host.Tests.Signals.csproj +++ b/tests/Tgstation.Server.Host.Tests.Signals/Tgstation.Server.Host.Tests.Signals.csproj @@ -1,4 +1,8 @@ + + true + + From a0ee1b35a42c257d04bdba3ead32c1f66ef652a9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 14 Nov 2023 22:10:15 -0500 Subject: [PATCH 199/717] Enable NRT on `Tgstation.Server.Common` --- src/Tgstation.Server.Common/Tgstation.Server.Common.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tgstation.Server.Common/Tgstation.Server.Common.csproj b/src/Tgstation.Server.Common/Tgstation.Server.Common.csproj index 07b8b364a24..b77bdc4dc15 100644 --- a/src/Tgstation.Server.Common/Tgstation.Server.Common.csproj +++ b/src/Tgstation.Server.Common/Tgstation.Server.Common.csproj @@ -4,6 +4,7 @@ $(TgsNugetNetFramework) $(TgsCommonLibraryVersion) + enable Common functions for tgstation-server. web tgstation-server tgstation ss13 byond client http $(TGS_NUGET_RELEASE_NOTES_COMMON) From c5fff694d79d997d7caf517ed4c7c6efb0e5a664 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 14 Nov 2023 23:11:33 -0500 Subject: [PATCH 200/717] Make the host watchdog use nullable references --- build/Version.props | 2 +- .../PosixSignalChecker.cs | 2 +- src/Tgstation.Server.Host.Console/Program.cs | 4 +- .../Tgstation.Server.Host.Console.csproj | 1 + src/Tgstation.Server.Host.Service/Program.cs | 13 +- .../ServerService.cs | 199 +++-------------- .../ServiceLifetime.cs | 200 ++++++++++++++++++ .../Tgstation.Server.Host.Service.csproj | 1 + .../ISignalChecker.cs | 4 +- .../IWatchdog.cs | 4 +- .../NoopSignalChecker.cs | 6 +- .../Tgstation.Server.Host.Watchdog.csproj | 1 + .../Watchdog.cs | 44 +++- .../TestServerService.cs | 17 +- 14 files changed, 296 insertions(+), 202 deletions(-) create mode 100644 src/Tgstation.Server.Host.Service/ServiceLifetime.cs diff --git a/build/Version.props b/build/Version.props index f75f23d2397..c27dc59c942 100644 --- a/build/Version.props +++ b/build/Version.props @@ -11,7 +11,7 @@ 15.0.0 7.0.0 5.7.0 - 1.4.0 + 1.4.1 1.2.1 2.0.0 netstandard2.0 diff --git a/src/Tgstation.Server.Host.Console/PosixSignalChecker.cs b/src/Tgstation.Server.Host.Console/PosixSignalChecker.cs index e037b5936fb..b18ece3c03f 100644 --- a/src/Tgstation.Server.Host.Console/PosixSignalChecker.cs +++ b/src/Tgstation.Server.Host.Console/PosixSignalChecker.cs @@ -31,7 +31,7 @@ public PosixSignalChecker(ILogger logger) } /// - public async ValueTask CheckSignals(Func startChild, CancellationToken cancellationToken) + public async ValueTask CheckSignals(Func startChild, CancellationToken cancellationToken) { var (childPid, _) = startChild?.Invoke(null) ?? throw new ArgumentNullException(nameof(startChild)); var signalTcs = new TaskCompletionSource(); diff --git a/src/Tgstation.Server.Host.Console/Program.cs b/src/Tgstation.Server.Host.Console/Program.cs index e142de81be4..c8383865af4 100644 --- a/src/Tgstation.Server.Host.Console/Program.cs +++ b/src/Tgstation.Server.Host.Console/Program.cs @@ -38,7 +38,7 @@ static Program() /// A representing the running operation. internal static async Task Main(string[] args) { - System.Console.Title = $"{Constants.CanonicalPackageName} Host Watchdog v{Assembly.GetExecutingAssembly().GetName().Version.Semver()}"; + System.Console.Title = $"{Constants.CanonicalPackageName} Host Watchdog v{Assembly.GetExecutingAssembly().GetName().Version?.Semver()}"; var arguments = new List(args); var trace = arguments.Remove("--trace-host-watchdog"); @@ -61,7 +61,7 @@ internal static async Task Main(string[] args) } using var cts = new CancellationTokenSource(); - void AppDomainHandler(object a, EventArgs b) => cts.Cancel(); + void AppDomainHandler(object? a, EventArgs b) => cts.Cancel(); AppDomain.CurrentDomain.ProcessExit += AppDomainHandler; try { 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 92902912bb3..3cbf1c1a163 100644 --- a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj +++ b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj @@ -5,6 +5,7 @@ Exe $(TgsFrameworkVersion) $(TgsCoreVersion) + enable false ../../build/uac_elevation_manifest.xml diff --git a/src/Tgstation.Server.Host.Service/Program.cs b/src/Tgstation.Server.Host.Service/Program.cs index 9e6deaeb633..c2f72b09010 100644 --- a/src/Tgstation.Server.Host.Service/Program.cs +++ b/src/Tgstation.Server.Host.Service/Program.cs @@ -77,7 +77,7 @@ sealed class Program /// The --passthroughargs or -p option. ///
[Option(ShortName = "p", Description = "Arguments passed to main host process")] - public string PassthroughArgs { get; set; } + public string? PassthroughArgs { get; set; } /// /// Entrypoint for the application. @@ -157,7 +157,7 @@ public async Task OnExecuteAsync() /// Runs sc.exe to either uninstall a given or install the running . /// /// The name of a service to uninstall. - void InvokeSC(string serviceToUninstall) + void InvokeSC(string? serviceToUninstall) { using var installer = new ServiceInstaller(); if (serviceToUninstall != null) @@ -172,6 +172,9 @@ void InvokeSC(string serviceToUninstall) Assembly.GetExecutingAssembly().Location); var assemblyDirectory = Path.GetDirectoryName(fullPathToAssembly); + if (assemblyDirectory == null) + throw new InvalidOperationException($"Failed to resolve directory name of {assemblyDirectory}"); + var assemblyNameWithoutExtension = Path.GetFileNameWithoutExtension(fullPathToAssembly); var exePath = Path.Combine(assemblyDirectory, $"{assemblyNameWithoutExtension}.exe"); @@ -260,10 +263,8 @@ void RestartService(ServiceController serviceController) var stop = !Detach; if (!stop) { - serviceController.ExecuteCommand( - PipeCommands.GetServiceCommandId( - PipeCommands.CommandDetachingShutdown) - .Value); + var serviceControllerCommand = PipeCommands.GetServiceCommandId(PipeCommands.CommandDetachingShutdown); + serviceController.ExecuteCommand(serviceControllerCommand!.Value); serviceController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30)); if (serviceController.Status != ServiceControllerStatus.Stopped) stop = true; diff --git a/src/Tgstation.Server.Host.Service/ServerService.cs b/src/Tgstation.Server.Host.Service/ServerService.cs index 8f5554304fe..56491187fbb 100644 --- a/src/Tgstation.Server.Host.Service/ServerService.cs +++ b/src/Tgstation.Server.Host.Service/ServerService.cs @@ -1,20 +1,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; -using System.IO.Pipes; -using System.Linq; using System.Runtime.Versioning; using System.ServiceProcess; -using System.Text; using System.Threading; -using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.EventLog; using Tgstation.Server.Common; -using Tgstation.Server.Host.Common; using Tgstation.Server.Host.Watchdog; namespace Tgstation.Server.Host.Service @@ -23,7 +17,7 @@ namespace Tgstation.Server.Host.Service /// Represents a as a . ///
[SupportedOSPlatform("windows")] - sealed class ServerService : ServiceBase, ISignalChecker + sealed class ServerService : ServiceBase { /// /// The canonical windows service name. @@ -36,44 +30,21 @@ sealed class ServerService : ServiceBase, ISignalChecker readonly IWatchdogFactory watchdogFactory; /// - /// The of command line arguments the service was invoked with. - /// - readonly string[] commandLineArguments; - - /// - /// The minimum for the . - /// - readonly LogLevel minimumLogLevel; - - /// - /// The used by the . - /// - ILoggerFactory loggerFactory; - - /// - /// The for the . - /// - ILogger logger; - - /// - /// The that represents the running . - /// - Task watchdogTask; - - /// - /// The for the . + /// The used by the . /// - CancellationTokenSource cancellationTokenSource; + readonly Lazy loggerFactory; /// - /// The for sending to the server process. + /// The of command line arguments the service was invoked with. /// - AnonymousPipeServerStream commandPipeServer; + readonly string[] commandLineArguments; /// - /// The for receiving the . + /// The active . /// - AnonymousPipeServerStream readyPipeServer; +#pragma warning disable CA2213 // Disposable fields should be disposed + volatile ServiceLifetime? serviceLifetime; +#pragma warning restore CA2213 // Disposable fields should be disposed /// /// Initializes a new instance of the class. @@ -85,21 +56,15 @@ public ServerService(IWatchdogFactory watchdogFactory, string[] commandLineArgum { this.watchdogFactory = watchdogFactory ?? throw new ArgumentNullException(nameof(watchdogFactory)); this.commandLineArguments = commandLineArguments ?? throw new ArgumentNullException(nameof(commandLineArguments)); - this.minimumLogLevel = minimumLogLevel; - ServiceName = Name; - } - /// - public async ValueTask CheckSignals(Func startChildAndGetPid, CancellationToken cancellationToken) - { - await using (commandPipeServer = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable)) - await using (readyPipeServer = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable)) + ServiceName = Name; + loggerFactory = new Lazy(() => LoggerFactory.Create(builder => builder.AddEventLog(new EventLogSettings { - var (_, lifetimeTask) = startChildAndGetPid($"--Internal:CommandPipe={commandPipeServer.GetClientHandleAsString()} --Internal:ReadyPipe={readyPipeServer.GetClientHandleAsString()}"); - commandPipeServer.DisposeLocalCopyOfClientHandle(); - readyPipeServer.DisposeLocalCopyOfClientHandle(); - await lifetimeTask; - } + LogName = EventLog.Log, + MachineName = EventLog.MachineName, + SourceName = EventLog.Source, + Filter = (message, logLevel) => logLevel >= minimumLogLevel, + }))); } /// @@ -112,53 +77,21 @@ protected override void Dispose(bool disposing) { if (disposing) { - loggerFactory?.Dispose(); - cancellationTokenSource?.Dispose(); - commandPipeServer?.Dispose(); - readyPipeServer?.Dispose(); + OnStop(); + + if (loggerFactory.IsValueCreated) + loggerFactory.Value.Dispose(); } base.Dispose(disposing); } /// - protected override void OnCustomCommand(int command) - { - var commandsToCheck = PipeCommands.AllCommands; - foreach (var stringCommand in commandsToCheck) - { - var commandId = PipeCommands.GetServiceCommandId(stringCommand); - if (command == commandId) - { - SendCommandToHostThroughPipe(stringCommand); - return; - } - } - - logger.LogWarning("Received unknown service command: {command}", command); - } + protected override void OnCustomCommand(int command) => serviceLifetime!.HandleCustomCommand(command); /// protected override void OnStart(string[] args) { - if (loggerFactory == null) - { - loggerFactory = LoggerFactory.Create(builder => builder.AddEventLog(new EventLogSettings - { - LogName = EventLog.Log, - MachineName = EventLog.MachineName, - SourceName = EventLog.Source, - Filter = (message, logLevel) => logLevel >= minimumLogLevel, - })); - - logger = loggerFactory.CreateLogger(); - } - - var watchdog = watchdogFactory.CreateWatchdog(this, loggerFactory); - - cancellationTokenSource?.Dispose(); - cancellationTokenSource = new CancellationTokenSource(); - var newArgs = new List(commandLineArguments.Length + args.Length + 1) { "--General:SetupWizardMode=Never", @@ -167,94 +100,18 @@ protected override void OnStart(string[] args) newArgs.AddRange(commandLineArguments); newArgs.AddRange(args); - watchdogTask = RunWatchdog(watchdog, newArgs.ToArray(), cancellationTokenSource.Token); - - if (!watchdogTask.IsCompleted && watchdog.InitialHostVersion >= new Version(5, 14, 0)) - { - logger.LogInformation("Waiting for host to finish starting..."); - using var streamReader = new StreamReader( - readyPipeServer, - Encoding.UTF8, - leaveOpen: true); - - var line = streamReader.ReadLine(); // Intentionally blocking service startup - logger.LogDebug("Pipe read: {line}", line); - } - - // Maybe we'll use this pipe more in the future, but for now leaving it open is just a resource waste - readyPipeServer.Dispose(); + serviceLifetime = new ServiceLifetime( + Stop, + signalChecker => watchdogFactory.CreateWatchdog(signalChecker, loggerFactory.Value), + loggerFactory.Value.CreateLogger(), + args); } /// protected override void OnStop() { - cancellationTokenSource.Cancel(); - watchdogTask.GetAwaiter().GetResult(); - } - - /// - /// Executes the , stopping the service if it exits. - /// - /// The to run. - /// The arguments for the . - /// The for the operation. - /// A representing the running operation. - async Task RunWatchdog(IWatchdog watchdog, string[] args, CancellationToken cancellationToken) - { - await watchdog.RunAsync(false, args, cancellationToken); - - async void StopServiceAsync() - { - try - { - await Task.Run(Stop, cancellationToken); // DCT intentional - } - catch (OperationCanceledException ex) - { - logger.LogTrace(ex, "Stopping service cancelled!"); - } - catch (Exception ex) - { - logger.LogError(ex, "Error stopping service!"); - } - } - - StopServiceAsync(); - } - - /// - /// Sends a command to the main server process. - /// - /// One of the . - void SendCommandToHostThroughPipe(string command) - { - var localPipeServer = commandPipeServer; - if (localPipeServer == null) - { - logger.LogWarning("Unable to send command \"{command}\" to main server process. Is the service running?", command); - return; - } - - logger.LogDebug("Send command: {command}", command); - try - { - var encoding = Encoding.UTF8; - using var streamWriter = new StreamWriter( - localPipeServer, - encoding, - PipeCommands - .AllCommands - .Select( - command => encoding.GetByteCount( - command + Environment.NewLine)) - .Max(), - true); - streamWriter.WriteLine(command); - } - catch (Exception ex) - { - logger.LogError(ex, "Error attempting to send command \"{command}\"", command); - } + var oldLifetime = Interlocked.Exchange(ref serviceLifetime, null); + oldLifetime?.DisposeAsync().GetAwaiter().GetResult(); } } } diff --git a/src/Tgstation.Server.Host.Service/ServiceLifetime.cs b/src/Tgstation.Server.Host.Service/ServiceLifetime.cs new file mode 100644 index 00000000000..efc058fbaab --- /dev/null +++ b/src/Tgstation.Server.Host.Service/ServiceLifetime.cs @@ -0,0 +1,200 @@ +using System; +using System.IO; +using System.IO.Pipes; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.Extensions.Logging; + +using Tgstation.Server.Host.Common; +using Tgstation.Server.Host.Watchdog; + +namespace Tgstation.Server.Host.Service +{ + /// + /// Represents the lifetime of the service. + /// + sealed class ServiceLifetime : ISignalChecker, IAsyncDisposable + { + /// + /// The for the . + /// + readonly ILogger logger; + + /// + /// The that represents the running . + /// + readonly Task watchdogTask; + + /// + /// The for the . + /// + readonly CancellationTokenSource cancellationTokenSource; + + /// + /// The for sending to the server process. + /// + AnonymousPipeServerStream? commandPipeServer; + + /// + /// The for receiving the . + /// + AnonymousPipeServerStream? readyPipeServer; + + /// + /// Initializes a new instance of the class. + /// + /// An to manually stop the service. + /// A taking a and returning the to run. + /// The value of . + /// The arguments for the . + public ServiceLifetime(Action stopService, Func watchdogFactory, ILogger logger, string[] args) + { + ArgumentNullException.ThrowIfNull(stopService); + ArgumentNullException.ThrowIfNull(watchdogFactory); + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + ArgumentNullException.ThrowIfNull(args); + + cancellationTokenSource = new CancellationTokenSource(); + watchdogTask = RunWatchdog( + stopService, + watchdogFactory(this), + args, + cancellationTokenSource.Token); + } + + /// + public async ValueTask DisposeAsync() + { + cancellationTokenSource.Cancel(); + await watchdogTask; + cancellationTokenSource.Dispose(); + + if (commandPipeServer != null) + await commandPipeServer.DisposeAsync(); + + if (readyPipeServer != null) + await readyPipeServer.DisposeAsync(); + } + + /// + public async ValueTask CheckSignals(Func startChildAndGetPid, CancellationToken cancellationToken) + { + try + { + await using (commandPipeServer = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable)) + await using (readyPipeServer = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable)) + { + var (_, lifetimeTask) = startChildAndGetPid($"--Internal:CommandPipe={commandPipeServer.GetClientHandleAsString()} --Internal:ReadyPipe={readyPipeServer.GetClientHandleAsString()}"); + commandPipeServer.DisposeLocalCopyOfClientHandle(); + readyPipeServer.DisposeLocalCopyOfClientHandle(); + await lifetimeTask; + } + } + finally + { + readyPipeServer = null; + commandPipeServer = null; + } + } + + /// + /// Handle a custom service . + /// + /// The command sent to the service. + public void HandleCustomCommand(int command) + { + var commandsToCheck = PipeCommands.AllCommands; + foreach (var stringCommand in commandsToCheck) + { + var commandId = PipeCommands.GetServiceCommandId(stringCommand); + if (command == commandId) + { + SendCommandToHostThroughPipe(stringCommand); + return; + } + } + + logger.LogWarning("Received unknown service command: {command}", command); + } + + /// + /// Executes the , stopping the service if it exits. + /// + /// An to manually stop the service. + /// The to run. + /// The arguments for the . + /// The for the operation. + /// A representing the running operation. + async Task RunWatchdog(Action stopService, IWatchdog watchdog, string[] args, CancellationToken cancellationToken) + { + var localWatchdogTask = watchdog.RunAsync(false, args, cancellationToken); + + if (!localWatchdogTask.IsCompleted && (await watchdog.InitialHostVersion) >= new Version(5, 14, 0)) + if (readyPipeServer != null) + { + logger.LogInformation("Waiting for host to finish starting..."); + using var streamReader = new StreamReader( + readyPipeServer, + Encoding.UTF8, + leaveOpen: true); + + var line = streamReader.ReadLine(); // Intentionally blocking service startup + logger.LogDebug("Pipe read: {line}", line); + + // Maybe we'll use this pipe more in the future, but for now leaving it open is just a resource waste + readyPipeServer.Dispose(); + } + else + logger.LogError("Watchdog started and ready pipe was not initialized!"); + + await localWatchdogTask; + + try + { + stopService(); + } + catch (Exception ex) + { + logger.LogError(ex, "Error stopping service!"); + } + } + + /// + /// Sends a command to the main server process. + /// + /// One of the . + void SendCommandToHostThroughPipe(string command) + { + var localPipeServer = commandPipeServer; + if (localPipeServer == null) + { + logger.LogWarning("Unable to send command \"{command}\" to main server process. Is the service running?", command); + return; + } + + logger.LogDebug("Send command: {command}", command); + try + { + var encoding = Encoding.UTF8; + using var streamWriter = new StreamWriter( + localPipeServer, + encoding, + PipeCommands + .AllCommands + .Select( + command => encoding.GetByteCount( + command + Environment.NewLine)) + .Max(), + true); + streamWriter.WriteLine(command); + } + catch (Exception ex) + { + logger.LogError(ex, "Error attempting to send command \"{command}\"", command); + } + } + } +} 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 aa98536f387..54710f6b47c 100644 --- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj +++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj @@ -4,6 +4,7 @@ WinExe win-x86;win-x64 + enable $(TgsFrameworkVersion) $(TgsCoreVersion) diff --git a/src/Tgstation.Server.Host.Watchdog/ISignalChecker.cs b/src/Tgstation.Server.Host.Watchdog/ISignalChecker.cs index b23295dd0fd..2b8d42ee809 100644 --- a/src/Tgstation.Server.Host.Watchdog/ISignalChecker.cs +++ b/src/Tgstation.Server.Host.Watchdog/ISignalChecker.cs @@ -12,9 +12,9 @@ public interface ISignalChecker /// /// Relays signals received to the host process. /// - /// An to start the main process. It accepts an optional additional command line argument as a paramter and returns it's and lifetime . + /// An to start the main process. It accepts an optional additional command line argument as a paramter and returns it's and lifetime . Must be called. /// The for the operation. /// A representing the running operation. - ValueTask CheckSignals(Func startChild, CancellationToken cancellationToken); + ValueTask CheckSignals(Func startChildAndGetPid, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host.Watchdog/IWatchdog.cs b/src/Tgstation.Server.Host.Watchdog/IWatchdog.cs index dadff2c41b3..c9f9e89da90 100644 --- a/src/Tgstation.Server.Host.Watchdog/IWatchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/IWatchdog.cs @@ -10,9 +10,9 @@ namespace Tgstation.Server.Host.Watchdog public interface IWatchdog { /// - /// Gets the current version of the host process. Set once begins and doesn't immediately return . + /// Gets a resulting in the current version of the host process. Guaranteed to complete once begins and doesn't immediately return . /// - Version InitialHostVersion { get; } + Task InitialHostVersion { get; } /// /// Run the . diff --git a/src/Tgstation.Server.Host.Watchdog/NoopSignalChecker.cs b/src/Tgstation.Server.Host.Watchdog/NoopSignalChecker.cs index fa5dd56f946..270cf633807 100644 --- a/src/Tgstation.Server.Host.Watchdog/NoopSignalChecker.cs +++ b/src/Tgstation.Server.Host.Watchdog/NoopSignalChecker.cs @@ -10,10 +10,10 @@ namespace Tgstation.Server.Host.Watchdog public sealed class NoopSignalChecker : ISignalChecker { /// - public ValueTask CheckSignals(Func startChild, CancellationToken cancellationToken) + public ValueTask CheckSignals(Func startChildAndGetPid, CancellationToken cancellationToken) { - ArgumentNullException.ThrowIfNull(startChild); - startChild(null); + ArgumentNullException.ThrowIfNull(startChildAndGetPid); + startChildAndGetPid(null); return ValueTask.CompletedTask; } } 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 ae3b89cdb27..04f187c08e1 100644 --- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj +++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj @@ -3,6 +3,7 @@ $(TgsFrameworkVersion) + enable false $(TgsHostWatchdogVersion) diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index bab5e9a07be..a574a6ab6b1 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -20,7 +20,7 @@ namespace Tgstation.Server.Host.Watchdog sealed class Watchdog : IWatchdog { /// - public Version InitialHostVersion { get; private set; } + public Task InitialHostVersion => initialHostVersionTcs.Task; /// /// The for the . @@ -32,6 +32,11 @@ sealed class Watchdog : IWatchdog /// readonly ILogger logger; + /// + /// Backing for . + /// + readonly TaskCompletionSource initialHostVersionTcs; + /// /// Initializes a new instance of the class. /// @@ -41,6 +46,8 @@ public Watchdog(ISignalChecker signalChecker, ILogger logger) { this.signalChecker = signalChecker ?? throw new ArgumentNullException(nameof(signalChecker)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + + initialHostVersionTcs = new TaskCompletionSource(); } /// @@ -54,7 +61,7 @@ public async ValueTask RunAsync(bool runConfigure, string[] args, Cancella currentProcessId = currentProc.Id; logger.LogDebug("PID: {pid}", currentProcessId); - string updateDirectory = null; + string? updateDirectory = null; try { var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); @@ -76,6 +83,11 @@ public async ValueTask RunAsync(bool runConfigure, string[] args, Cancella var executingAssembly = Assembly.GetExecutingAssembly(); var rootLocation = Path.GetDirectoryName(executingAssembly.Location); + if (rootLocation == null) + { + logger.LogCritical("Failed to get the directory name of the executing assembly: {location}", executingAssembly.Location); + return false; + } var assemblyStoragePath = Path.Combine(rootLocation, "lib"); // always always next to watchdog @@ -119,9 +131,18 @@ public async ValueTask RunAsync(bool runConfigure, string[] args, Cancella return false; } - InitialHostVersion = Version.Parse(FileVersionInfo.GetVersionInfo(assemblyPath).FileVersion); + var fileVersion = FileVersionInfo.GetVersionInfo(assemblyPath).FileVersion; + if (fileVersion == null) + { + logger.LogCritical("Failed to parse version info from {assemblyPath}!", assemblyPath); + return false; + } + + initialHostVersionTcs.SetResult( + Version.Parse( + fileVersion)); - var watchdogVersion = executingAssembly.GetName().Version.Semver().ToString(); + var watchdogVersion = executingAssembly.GetName().Version?.Semver().ToString(); while (!cancellationToken.IsCancellationRequested) using (logger.BeginScope("Host invocation")) @@ -158,8 +179,8 @@ public async ValueTask RunAsync(bool runConfigure, string[] args, Cancella var killedHostProcess = false; try { - Task processTask = null; - (int, Task) StartProcess(string additionalArg) + Task? processTask = null; + (int, Task) StartProcess(string? additionalArg) { if (additionalArg != null) process.StartInfo.Arguments += $" {additionalArg}"; @@ -199,7 +220,7 @@ public async ValueTask RunAsync(bool runConfigure, string[] args, Cancella var checkerTask = signalChecker.CheckSignals(StartProcess, cts.Token); try { - await processTask; + await processTask!; } finally { @@ -338,10 +359,11 @@ public async ValueTask RunAsync(bool runConfigure, string[] args, Cancella catch (OperationCanceledException ex) { logger.LogDebug(ex, "Exiting due to cancellation..."); - if (!Directory.Exists(updateDirectory)) - File.Delete(updateDirectory); - else - Directory.Delete(updateDirectory, true); + if (updateDirectory != null) + if (!Directory.Exists(updateDirectory)) + File.Delete(updateDirectory); + else + Directory.Delete(updateDirectory, true); } catch (Exception ex) { diff --git a/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs b/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs index 855870d4c82..6faf32f95eb 100644 --- a/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs +++ b/tests/Tgstation.Server.Host.Service.Tests/TestServerService.cs @@ -39,15 +39,25 @@ public void TestRun() var childStarted = false; ISignalChecker signalChecker = null; - mockWatchdog.Setup(x => x.RunAsync(false, It.IsNotNull(), It.IsAny())).Callback((bool x, string[] _, CancellationToken token) => + var hostVersionTcs = new TaskCompletionSource(); + var hostLifetimeTcs = new TaskCompletionSource(); + + mockWatchdog.Setup(x => x.RunAsync(false, It.IsNotNull(), It.IsAny())).Returns(async (bool x, string[] _, CancellationToken token) => { + hostVersionTcs.SetResult(typeof(ServerService).Assembly.GetName().Version); + cancellationToken = token; + cancellationToken.Register(() => hostLifetimeTcs.SetResult(true)); signalCheckerTask = signalChecker.CheckSignals(additionalArgs => { childStarted = true; - return (123, Task.CompletedTask); + return (123, hostLifetimeTcs.Task); }, cancellationToken).AsTask(); - }).ReturnsAsync(true).Verifiable(); + + await signalCheckerTask; + return true; + }).Verifiable(); + mockWatchdog.SetupGet(x => x.InitialHostVersion).Returns(hostVersionTcs.Task); var mockWatchdogFactory = new Mock(); mockWatchdogFactory.Setup(x => x.CreateWatchdog(It.IsNotNull(), It.IsNotNull())) @@ -68,6 +78,7 @@ public void TestRun() mockWatchdogFactory.VerifyAll(); Assert.IsTrue(signalCheckerTask.IsCompleted); + Assert.IsTrue(cancellationToken.IsCancellationRequested); } } } From 5c5b54e094b9f6c549e7a50accddf2d4a384d294 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 17 Nov 2023 12:23:37 -0500 Subject: [PATCH 201/717] Update to beta Stylecop Cleanup warnings --- build/SrcCommon.props | 2 +- src/Tgstation.Server.Api/Models/EngineType.cs | 2 +- src/Tgstation.Server.Api/Models/ErrorCode.cs | 8 ++-- .../Models/FieldPresence.cs | 2 +- .../Models/IrcPasswordType.cs | 6 +-- .../Models/OAuthProvider.cs | 10 ++--- .../Models/RemoteGitProvider.cs | 4 +- .../Models/Response/TokenResponse.cs | 2 +- .../Rights/AdministrationRights.cs | 2 +- .../Rights/ChatBotRights.cs | 4 +- .../Rights/DreamDaemonRights.cs | 2 +- .../Rights/InstancePermissionSetRights.cs | 2 +- src/Tgstation.Server.Api/Rights/RightsType.cs | 18 ++++----- src/Tgstation.Server.Client/ApiClient.cs | 8 +--- .../Extensions/ValueTaskExtensions.cs | 2 +- .../ISignalChecker.cs | 2 +- .../Chat/Providers/DiscordProvider.cs | 2 +- .../Components/Chat/Providers/IrcProvider.cs | 2 +- .../Components/Engine/ByondInstallerBase.cs | 4 +- .../Engine/WindowsByondInstaller.cs | 2 +- .../Components/Events/EventType.cs | 40 +++++++++---------- .../Interop/Bridge/BridgeCommandType.cs | 2 +- .../Components/Interop/DMApiConstants.cs | 2 +- .../Interop/Topic/TopicParameters.cs | 4 +- .../Components/Repository/Repository.cs | 2 +- .../Components/Session/ApiValidationStatus.cs | 12 +++--- .../Components/Session/RebootState.cs | 6 +-- .../Session/SessionControllerFactory.cs | 2 +- .../Components/Watchdog/MonitorAction.cs | 8 ++-- .../Watchdog/MonitorActivationReason.cs | 8 ++-- .../Configuration/DatabaseType.cs | 10 ++--- .../Extensions/TaskExtensions.cs | 2 +- .../IO/BufferedFileStreamProvider.cs | 8 ++-- .../IO/DefaultIOManager.cs | 2 +- .../Models/CompileJob.cs | 2 +- src/Tgstation.Server.Host/Models/Instance.cs | 2 +- src/Tgstation.Server.Host/Models/Job.cs | 6 +-- src/Tgstation.Server.Host/Models/UserGroup.cs | 2 +- .../Security/OAuth/DiscordOAuthValidator.cs | 6 +-- .../Security/OAuth/GenericOAuthValidator.cs | 4 +- .../Security/OAuth/GitHubOAuthValidator.cs | 2 +- .../OAuth/InvisionCommunityOAuthValidator.cs | 6 +-- .../Security/OAuth/KeycloakOAuthValidator.cs | 6 +-- .../Security/OAuth/TGForumsOAuthValidator.cs | 6 +-- .../Swarm/SwarmConstants.cs | 2 +- .../Swarm/SwarmService.cs | 20 +++++----- .../System/AssemblyInformationProvider.cs | 2 +- .../System/ProcessExecutor.cs | 2 +- .../System/WindowsNetworkPromptReaper.cs | 13 +++--- .../Transfer/FileTransferService.cs | 2 +- .../Utils/GitHub/GitHubClientFactory.cs | 12 +++--- .../Utils/GitHub/GitHubServiceFactory.cs | 2 +- 52 files changed, 144 insertions(+), 147 deletions(-) diff --git a/build/SrcCommon.props b/build/SrcCommon.props index fb1f8c29d5c..d6e835dad08 100644 --- a/build/SrcCommon.props +++ b/build/SrcCommon.props @@ -17,7 +17,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Tgstation.Server.Api/Models/EngineType.cs b/src/Tgstation.Server.Api/Models/EngineType.cs index 67410c1d470..df4b3ab3aa2 100644 --- a/src/Tgstation.Server.Api/Models/EngineType.cs +++ b/src/Tgstation.Server.Api/Models/EngineType.cs @@ -6,7 +6,7 @@ public enum EngineType { /// - /// Build your own net dream, + /// Build your own net dream. /// Byond, diff --git a/src/Tgstation.Server.Api/Models/ErrorCode.cs b/src/Tgstation.Server.Api/Models/ErrorCode.cs index 52de54d77e6..886816346a7 100644 --- a/src/Tgstation.Server.Api/Models/ErrorCode.cs +++ b/src/Tgstation.Server.Api/Models/ErrorCode.cs @@ -36,7 +36,7 @@ public enum ErrorCode : uint IOError, /// - /// The failed to validate! + /// The failed to validate. /// [Description("A header validation error occurred!")] BadHeaders, @@ -324,7 +324,7 @@ public enum ErrorCode : uint EngineNoVersionsInstalled, /// - /// The DMAPI never validated itself + /// The DMAPI never validated itself. /// [Description("DMAPI validation failed! See FAQ at https://github.com/tgstation/tgstation-server/discussions/1695")] DeploymentNeverValidated, @@ -360,7 +360,7 @@ public enum ErrorCode : uint DeploymentExitCode, /// - /// Deployment already in progress + /// Deployment already in progress. /// [Description("There is already a deployment operation in progress!")] DeploymentInProgress, @@ -600,7 +600,7 @@ public enum ErrorCode : uint FileUploadExpired, /// - /// Tried to update a user to have both a and + /// Tried to update a user to have both a and . /// [Description("A user may not have both a permissionSet and group!")] UserGroupAndPermissionSet, diff --git a/src/Tgstation.Server.Api/Models/FieldPresence.cs b/src/Tgstation.Server.Api/Models/FieldPresence.cs index 11db2cd2cb5..e09ac60975b 100644 --- a/src/Tgstation.Server.Api/Models/FieldPresence.cs +++ b/src/Tgstation.Server.Api/Models/FieldPresence.cs @@ -6,7 +6,7 @@ public enum FieldPresence { /// - /// The field is optional + /// The field is optional. /// Optional, diff --git a/src/Tgstation.Server.Api/Models/IrcPasswordType.cs b/src/Tgstation.Server.Api/Models/IrcPasswordType.cs index ad6ac6d9c20..add54b1565f 100644 --- a/src/Tgstation.Server.Api/Models/IrcPasswordType.cs +++ b/src/Tgstation.Server.Api/Models/IrcPasswordType.cs @@ -6,17 +6,17 @@ public enum IrcPasswordType { /// - /// Use server authentication + /// Use server authentication. /// Server, /// - /// Use PLAIN sasl authentication + /// Use PLAIN sasl authentication. /// Sasl, /// - /// Use NickServ authentication + /// Use NickServ authentication. /// NickServ, } diff --git a/src/Tgstation.Server.Api/Models/OAuthProvider.cs b/src/Tgstation.Server.Api/Models/OAuthProvider.cs index a6dfbe07bb7..0581cf33698 100644 --- a/src/Tgstation.Server.Api/Models/OAuthProvider.cs +++ b/src/Tgstation.Server.Api/Models/OAuthProvider.cs @@ -10,27 +10,27 @@ namespace Tgstation.Server.Api.Models public enum OAuthProvider { /// - /// https://github.com + /// https://github.com. /// GitHub, /// - /// https://discord.com + /// https://discord.com. /// Discord, /// - /// https://tgstation13.org + /// https://tgstation13.org. /// TGForums, /// - /// https://www.keycloak.org + /// https://www.keycloak.org. /// Keycloak, /// - /// https://invisioncommunity.com/ + /// https://invisioncommunity.com. /// InvisionCommunity, } diff --git a/src/Tgstation.Server.Api/Models/RemoteGitProvider.cs b/src/Tgstation.Server.Api/Models/RemoteGitProvider.cs index c6df292adfb..b90016a4229 100644 --- a/src/Tgstation.Server.Api/Models/RemoteGitProvider.cs +++ b/src/Tgstation.Server.Api/Models/RemoteGitProvider.cs @@ -11,12 +11,12 @@ public enum RemoteGitProvider Unknown, /// - /// Remote provider is GitHub.com + /// Remote provider is GitHub.com. /// GitHub, /// - /// Remote provider is GitLab.com + /// Remote provider is GitLab.com. /// GitLab, } diff --git a/src/Tgstation.Server.Api/Models/Response/TokenResponse.cs b/src/Tgstation.Server.Api/Models/Response/TokenResponse.cs index c3908e95185..f81066741a4 100644 --- a/src/Tgstation.Server.Api/Models/Response/TokenResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/TokenResponse.cs @@ -16,6 +16,6 @@ public sealed class TokenResponse /// Parses the as a . /// /// A new based on . - public JsonWebToken ParseJwt() => new (Bearer); + public JsonWebToken ParseJwt() => new(Bearer); } } diff --git a/src/Tgstation.Server.Api/Rights/AdministrationRights.cs b/src/Tgstation.Server.Api/Rights/AdministrationRights.cs index 018a239e8e2..ed530eee44a 100644 --- a/src/Tgstation.Server.Api/Rights/AdministrationRights.cs +++ b/src/Tgstation.Server.Api/Rights/AdministrationRights.cs @@ -9,7 +9,7 @@ namespace Tgstation.Server.Api.Rights public enum AdministrationRights : ulong { /// - /// User has no rights + /// User has no rights. /// None = 0, diff --git a/src/Tgstation.Server.Api/Rights/ChatBotRights.cs b/src/Tgstation.Server.Api/Rights/ChatBotRights.cs index d94106ead89..d00af08c86b 100644 --- a/src/Tgstation.Server.Api/Rights/ChatBotRights.cs +++ b/src/Tgstation.Server.Api/Rights/ChatBotRights.cs @@ -29,7 +29,7 @@ public enum ChatBotRights : ulong WriteChannels = 1 << 2, /// - /// User can change + /// User can change . /// WriteConnectionString = 1 << 3, @@ -39,7 +39,7 @@ public enum ChatBotRights : ulong ReadConnectionString = 1 << 4, /// - /// User can read all chat bot properties except + /// User can read all chat bot properties except . /// Read = 1 << 5, diff --git a/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs b/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs index 378783bf1e2..9af0522856f 100644 --- a/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs +++ b/src/Tgstation.Server.Api/Rights/DreamDaemonRights.cs @@ -74,7 +74,7 @@ public enum DreamDaemonRights : ulong SetStartupTimeout = 1 << 11, /// - /// User can change + /// User can change . /// SetHealthCheckInterval = 1 << 12, diff --git a/src/Tgstation.Server.Api/Rights/InstancePermissionSetRights.cs b/src/Tgstation.Server.Api/Rights/InstancePermissionSetRights.cs index 6562e383980..0b6e3b5f9a7 100644 --- a/src/Tgstation.Server.Api/Rights/InstancePermissionSetRights.cs +++ b/src/Tgstation.Server.Api/Rights/InstancePermissionSetRights.cs @@ -9,7 +9,7 @@ namespace Tgstation.Server.Api.Rights public enum InstancePermissionSetRights : ulong { /// - /// User has no rights/ + /// User has no rights. /// None = 0, diff --git a/src/Tgstation.Server.Api/Rights/RightsType.cs b/src/Tgstation.Server.Api/Rights/RightsType.cs index 1959a56e5b1..7c60417def4 100644 --- a/src/Tgstation.Server.Api/Rights/RightsType.cs +++ b/src/Tgstation.Server.Api/Rights/RightsType.cs @@ -6,47 +6,47 @@ public enum RightsType : ulong { /// - /// + /// . /// Administration, /// - /// + /// . /// InstanceManager, /// - /// + /// . /// Repository, /// - /// + /// . /// Engine, /// - /// + /// . /// DreamMaker, /// - /// + /// . /// DreamDaemon, /// - /// + /// . /// ChatBots, /// - /// + /// . /// Configuration, /// - /// + /// . /// InstancePermissionSet, } diff --git a/src/Tgstation.Server.Client/ApiClient.cs b/src/Tgstation.Server.Client/ApiClient.cs index f691dd0e905..e9824a433db 100644 --- a/src/Tgstation.Server.Client/ApiClient.cs +++ b/src/Tgstation.Server.Client/ApiClient.cs @@ -37,7 +37,7 @@ class ApiClient : IApiClient /// PATCH . /// /// HOW IS THIS NOT INCLUDED IN THE FRAMEWORK??!?!? - static readonly HttpMethod HttpPatch = new ("PATCH"); + static readonly HttpMethod HttpPatch = new("PATCH"); /// public Uri Url { get; } @@ -59,7 +59,7 @@ public TimeSpan Timeout /// /// The to use. /// - static readonly JsonSerializerSettings SerializerSettings = new () + static readonly JsonSerializerSettings SerializerSettings = new() { ContractResolver = new CamelCasePropertyNamesContractResolver(), Converters = new[] @@ -126,9 +126,7 @@ static void HandleBadResponse(HttpResponseMessage response, string json) } #pragma warning disable IDE0010 // Add missing cases -#pragma warning disable IDE0066 // Convert switch statement to expression switch (response.StatusCode) -#pragma warning restore IDE0066 // Convert switch statement to expression #pragma warning restore IDE0010 // Add missing cases { case HttpStatusCode.Unauthorized: @@ -310,9 +308,7 @@ public async ValueTask Upload(FileTicketResponse ticket, Stream? uploadStream, C using (memoryStream) { -#pragma warning disable CA2000 // Dispose objects before losing scope var streamContent = new StreamContent(uploadStream ?? memoryStream); -#pragma warning restore CA2000 // Dispose objects before losing scope try { await RunRequest( diff --git a/src/Tgstation.Server.Common/Extensions/ValueTaskExtensions.cs b/src/Tgstation.Server.Common/Extensions/ValueTaskExtensions.cs index 6cb8e6ad8ac..1dead09d935 100644 --- a/src/Tgstation.Server.Common/Extensions/ValueTaskExtensions.cs +++ b/src/Tgstation.Server.Common/Extensions/ValueTaskExtensions.cs @@ -138,7 +138,7 @@ public static async ValueTask WhenAll(IReadOnlyList tasks) } catch (Exception ex) { - exceptions ??= new (tasks.Count - i); + exceptions ??= new(tasks.Count - i); exceptions.Add(ex); } diff --git a/src/Tgstation.Server.Host.Watchdog/ISignalChecker.cs b/src/Tgstation.Server.Host.Watchdog/ISignalChecker.cs index 2b8d42ee809..5ba7f8dda58 100644 --- a/src/Tgstation.Server.Host.Watchdog/ISignalChecker.cs +++ b/src/Tgstation.Server.Host.Watchdog/ISignalChecker.cs @@ -15,6 +15,6 @@ public interface ISignalChecker /// An to start the main process. It accepts an optional additional command line argument as a paramter and returns it's and lifetime . Must be called. /// The for the operation. /// A representing the running operation. - ValueTask CheckSignals(Func startChildAndGetPid, CancellationToken cancellationToken); + ValueTask CheckSignals(Func startChildAndGetPid, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 943e8e10054..bda2228065b 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -337,7 +337,7 @@ public override async ValueTask new () + Embed CreateUpdatedEmbed(string message, Color color) => new() { Author = embed.Author, Colour = color, diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index 8bca821cf1b..e4fe37a93e1 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -351,7 +351,7 @@ await SendMessage( dbChannel, new List { - new () + new() { RealId = id.Value, IsAdminChannel = dbChannel.IsAdminChannel == true, diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index dcbbd9b0cdc..cf20d498a97 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -41,12 +41,12 @@ abstract class ByondInstallerBase : EngineInstallerBase /// /// The first of BYOND that supports the '-map-threads' parameter on DreamDaemon. /// - static readonly Version MapThreadsVersion = new (515, 1609); + static readonly Version MapThreadsVersion = new(515, 1609); /// /// for writing to files in the user's BYOND directory. /// - static readonly SemaphoreSlim UserFilesSemaphore = new (1); + static readonly SemaphoreSlim UserFilesSemaphore = new(1); /// protected override EngineType TargetEngineType => EngineType.Byond; diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 2af9b96a35f..0ebf63ff9fe 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -50,7 +50,7 @@ sealed class WindowsByondInstaller : ByondInstallerBase, IDisposable /// /// The first version of BYOND to ship with dd.exe on the Windows build. /// - public static Version DDExeVersion => new (515, 1598); + public static Version DDExeVersion => new(515, 1598); /// protected override string DreamMakerName => "dm.exe"; diff --git a/src/Tgstation.Server.Host/Components/Events/EventType.cs b/src/Tgstation.Server.Host/Components/Events/EventType.cs index 2d34b552c22..fa8321c7e02 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventType.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventType.cs @@ -6,92 +6,92 @@ public enum EventType { /// - /// Parameters: Reference name, commit sha + /// Parameters: Reference name, commit sha. /// [EventScript("RepoResetOrigin")] RepoResetOrigin, /// - /// Parameters: Checkout target + /// Parameters: Checkout target. /// [EventScript("RepoCheckout")] RepoCheckout, /// - /// No parameters + /// No parameters. /// [EventScript("RepoFetch")] RepoFetch, /// - /// Parameters: Test merge number, test merge target sha, merger message + /// Parameters: Test merge number, test merge target sha, merger message. /// [EventScript("RepoMergePullRequest")] RepoAddTestMerge, /// - /// Parameters: Absolute path to repository root + /// Parameters: Absolute path to repository root. /// /// Changes made to the repository during this event will be pushed to the tracked branch if no test merges are present. [EventScript("PreSynchronize")] RepoPreSynchronize, /// - /// Parameters: Version being installed + /// Parameters: Version being installed. /// [EventScript("ByondInstallStart", "EngineInstallStart")] EngineInstallStart, /// - /// Parameters: Error string + /// Parameters: Error string. /// [EventScript("ByondInstallFail", "EngineInstallFail")] EngineInstallFail, /// - /// Parameters: Old active version, new active version + /// Parameters: Old active version, new active version. /// [EventScript("ByondActiveVersionChange", "EngineActiveVersionChange")] EngineActiveVersionChange, /// - /// After the repo is copied, before CodeModifications are applied. Parameters: Game directory path, origin commit sha, engine version string + /// After the repo is copied, before CodeModifications are applied. Parameters: Game directory path, origin commit sha, engine version string. /// [EventScript("PreCompile")] CompileStart, /// - /// No parameters + /// No parameters. /// [EventScript("CompileCancelled")] CompileCancelled, /// - /// Parameters: Game directory path, "1" if compile succeeded and api validation failed, "0" otherwise, engine version string + /// Parameters: Game directory path, "1" if compile succeeded and api validation failed, "0" otherwise, engine version string. /// [EventScript("CompileFailure")] CompileFailure, /// - /// Parameters: Game directory path, engine version string + /// Parameters: Game directory path, engine version string. /// [EventScript("PostCompile")] CompileComplete, /// - /// No parameters + /// No parameters. /// [EventScript("InstanceAutoUpdateStart")] InstanceAutoUpdateStart, /// - /// Parameters: Base sha, target sha, base reference, target reference, all conflicting files + /// Parameters: Base sha, target sha, base reference, target reference, all conflicting files. /// [EventScript("RepoMergeConflict")] RepoMergeConflict, /// - /// No parameters + /// No parameters. /// [EventScript("DeploymentComplete")] DeploymentComplete, @@ -139,31 +139,31 @@ public enum EventType WorldPrime, /// - /// After DD has launched. Not the same as WatchdogLaunch. Parameters: PID of DreamDaemon + /// After DD has launched. Not the same as WatchdogLaunch. Parameters: PID of DreamDaemon. /// [EventScript("DreamDaemonLaunch")] DreamDaemonLaunch, /// - /// After a single submodule update is performed. Parameters: Updated submodule name + /// After a single submodule update is performed. Parameters: Updated submodule name. /// [EventScript("RepoSubmoduleUpdate")] RepoSubmoduleUpdate, /// - /// After CodeModifications are applied, before DreamMaker is run. Parameters: Game directory path, origin commit sha, engine version string + /// After CodeModifications are applied, before DreamMaker is run. Parameters: Game directory path, origin commit sha, engine version string. /// [EventScript("PreDreamMaker")] PreDreamMaker, /// - /// Whenever a deployment folder is deleted from disk. Parameters: Game directory path + /// Whenever a deployment folder is deleted from disk. Parameters: Game directory path. /// [EventScript("DeploymentCleanup")] DeploymentCleanup, /// - /// Whenever a deployment is about to be used by the game server. May fire multiple times per deployment. Parameters: Game directory path + /// Whenever a deployment is about to be used by the game server. May fire multiple times per deployment. Parameters: Game directory path. /// [EventScript("DeploymentActivation")] DeploymentActivation, diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeCommandType.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeCommandType.cs index 627d55d9949..8c18f74c397 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeCommandType.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeCommandType.cs @@ -16,7 +16,7 @@ public enum BridgeCommandType Startup, /// - /// DreamDaemon notifying the server is primed + /// DreamDaemon notifying the server is primed. /// Prime, diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs index 9cca307361c..2a59892180c 100644 --- a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs +++ b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs @@ -57,7 +57,7 @@ static class DMApiConstants /// /// for use when communicating with the DMAPI. /// - public static readonly JsonSerializerSettings SerializerSettings = new () + public static readonly JsonSerializerSettings SerializerSettings = new() { ContractResolver = new DefaultContractResolver { diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs index fff5453b0de..65c060b412d 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs @@ -88,7 +88,7 @@ or TopicCommandType.HealthCheck /// The value of . /// The created . public static TopicParameters CreateInstanceRenamedTopicParameters(string newInstanceName) - => new ( + => new( newInstanceName ?? throw new ArgumentNullException(nameof(newInstanceName)), TopicCommandType.InstanceRenamed); @@ -98,7 +98,7 @@ public static TopicParameters CreateInstanceRenamedTopicParameters(string newIns /// The value of . /// The created . public static TopicParameters CreateBroadcastParameters(string broadcastMessage) - => new ( + => new( broadcastMessage ?? throw new ArgumentNullException(nameof(broadcastMessage)), TopicCommandType.Broadcast); diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs index 6c4a619bf0e..a3b81d2bad7 100644 --- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs @@ -68,7 +68,7 @@ sealed class Repository : IRepository public string Reference => libGitRepo.Head.FriendlyName; /// - public Uri Origin => new (libGitRepo.Network.Remotes.First().Url); + public Uri Origin => new(libGitRepo.Network.Remotes.First().Url); /// /// The for the . diff --git a/src/Tgstation.Server.Host/Components/Session/ApiValidationStatus.cs b/src/Tgstation.Server.Host/Components/Session/ApiValidationStatus.cs index 74ea6b4c540..6b3c6db3573 100644 --- a/src/Tgstation.Server.Host/Components/Session/ApiValidationStatus.cs +++ b/src/Tgstation.Server.Host/Components/Session/ApiValidationStatus.cs @@ -6,32 +6,32 @@ enum ApiValidationStatus { /// - /// The DMAPI never contacted the server for validation + /// The DMAPI never contacted the server for validation. /// NeverValidated, /// - /// The server was contacted for validation but it was never requested + /// The server was contacted for validation but it was never requested. /// UnaskedValidationRequest, /// - /// The validation request was malformed + /// The validation request was malformed. /// BadValidationRequest, /// - /// Valid API. The game must be run with a minimum security level of + /// Valid API. The game must be run with a minimum security level of . /// RequiresSafe, /// - /// Valid API. The game must be run with a security level of + /// Valid API. The game must be run with a security level of . /// RequiresTrusted, /// - /// Valid API. The game must be run with a minimum security level of + /// Valid API. The game must be run with a minimum security level of . /// RequiresUltrasafe, diff --git a/src/Tgstation.Server.Host/Components/Session/RebootState.cs b/src/Tgstation.Server.Host/Components/Session/RebootState.cs index 0b58f492dda..030e8be98e8 100644 --- a/src/Tgstation.Server.Host/Components/Session/RebootState.cs +++ b/src/Tgstation.Server.Host/Components/Session/RebootState.cs @@ -6,17 +6,17 @@ public enum RebootState : int { /// - /// Run DreamDaemon's normal reboot process + /// Run DreamDaemon's normal reboot process. /// Normal = 0, /// - /// Shutdown DreamDaemon + /// Shutdown DreamDaemon. /// Shutdown = 1, /// - /// Restart the DreamDaemon process + /// Restart the DreamDaemon process. /// Restart = 2, } diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 9cd7fa15aad..a54f9f8874d 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -614,7 +614,7 @@ RuntimeInformation CreateRuntimeInformation( DreamDaemonSecurity securityLevel, DreamDaemonVisibility visibility, bool apiValidateOnly) - => new ( + => new( chatTrackingContext, dmbProvider, assemblyInformationProvider.Version, diff --git a/src/Tgstation.Server.Host/Components/Watchdog/MonitorAction.cs b/src/Tgstation.Server.Host/Components/Watchdog/MonitorAction.cs index 50c33760bb1..999df90fd18 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/MonitorAction.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/MonitorAction.cs @@ -6,22 +6,22 @@ enum MonitorAction { /// - /// The monitor should continue as normal + /// The monitor should continue as normal. /// Continue, /// - /// Skips the next call to HandleMonitorWakeup action + /// Skips the next call to HandleMonitorWakeup action. /// Skip, /// - /// The monitor should kill and restart both servers + /// The monitor should kill and restart both servers. /// Restart, /// - /// The monitor should stop checking actions for this iteration and continue its loop + /// The monitor should stop checking actions for this iteration and continue its loop. /// Break, diff --git a/src/Tgstation.Server.Host/Components/Watchdog/MonitorActivationReason.cs b/src/Tgstation.Server.Host/Components/Watchdog/MonitorActivationReason.cs index 9cd09acd7ab..1d9c760d13d 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/MonitorActivationReason.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/MonitorActivationReason.cs @@ -6,22 +6,22 @@ enum MonitorActivationReason { /// - /// The active server crashed or exited + /// The active server crashed or exited. /// ActiveServerCrashed, /// - /// The active server called /world/Reboot() + /// The active server called /world/Reboot(). /// ActiveServerRebooted, /// - /// A new .dmb was deployed + /// A new .dmb was deployed. /// NewDmbAvailable, /// - /// Server launch parameters were changed + /// Server launch parameters were changed. /// ActiveLaunchParametersUpdated, diff --git a/src/Tgstation.Server.Host/Configuration/DatabaseType.cs b/src/Tgstation.Server.Host/Configuration/DatabaseType.cs index 9b3f1c89ca5..ab2e6fcae61 100644 --- a/src/Tgstation.Server.Host/Configuration/DatabaseType.cs +++ b/src/Tgstation.Server.Host/Configuration/DatabaseType.cs @@ -6,27 +6,27 @@ public enum DatabaseType { /// - /// Use Microsoft SQL Server + /// Use Microsoft SQL Server. /// SqlServer, /// - /// Use MySQL + /// Use MySQL. /// MySql, /// - /// Use MariaDB + /// Use MariaDB. /// MariaDB, /// - /// Use Sqlite + /// Use Sqlite. /// Sqlite, /// - /// Use PostgresSql + /// Use PostgresSql. /// PostgresSql, } diff --git a/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs b/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs index 68f8f698744..55b6701dbbf 100644 --- a/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs @@ -10,7 +10,7 @@ static class TaskExtensions /// /// A that never completes. /// - static readonly TaskCompletionSource InfiniteTaskCompletionSource = new (); + static readonly TaskCompletionSource InfiniteTaskCompletionSource = new(); /// /// Gets a that never completes. diff --git a/src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs b/src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs index a369f410478..c3248698601 100644 --- a/src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs +++ b/src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs @@ -102,7 +102,7 @@ public async ValueTask GetOwnedResult(CancellationToken cancellati /// /// The for the operation. /// A resulting in and its . - async ValueTask<(MemoryStream, long)> GetResultInternal(CancellationToken cancellationToken) + async ValueTask<(MemoryStream Stream, long StreamLength)> GetResultInternal(CancellationToken cancellationToken) { if (!buffered) using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken)) @@ -115,15 +115,15 @@ public async ValueTask GetOwnedResult(CancellationToken cancellati await input.CopyToAsync(localBuffer, cancellationToken); localBuffer.Seek(0, SeekOrigin.Begin); buffered = true; - return (localBuffer, localBuffer.Length); + return (Stream: localBuffer, StreamLength: localBuffer.Length); } lock (semaphore) { var localBuffer = buffer ?? throw new ObjectDisposedException(nameof(BufferedFileStreamProvider)); return ( - localBuffer, - localBuffer.Length); + Stream: localBuffer, + StreamLength: localBuffer.Length); } } } diff --git a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs index 4d3089d4c80..4841980dd35 100644 --- a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs +++ b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs @@ -323,7 +323,7 @@ public Task GetLastModified(string path, CancellationToken cance TaskScheduler.Current); /// - public FileStream GetFileStream(string path, bool shareWrite) => new ( + public FileStream GetFileStream(string path, bool shareWrite) => new( ResolvePath(path), FileMode.Open, FileAccess.Read, diff --git a/src/Tgstation.Server.Host/Models/CompileJob.cs b/src/Tgstation.Server.Host/Models/CompileJob.cs index 8ff0ab466d1..59bc7c4d01a 100644 --- a/src/Tgstation.Server.Host/Models/CompileJob.cs +++ b/src/Tgstation.Server.Host/Models/CompileJob.cs @@ -82,7 +82,7 @@ public override Version DMApiVersion } /// - public CompileJobResponse ToApi() => new () + public CompileJobResponse ToApi() => new() { DirectoryName = DirectoryName, DmeName = DmeName, diff --git a/src/Tgstation.Server.Host/Models/Instance.cs b/src/Tgstation.Server.Host/Models/Instance.cs index 8acf4f15703..82cfd5c7072 100644 --- a/src/Tgstation.Server.Host/Models/Instance.cs +++ b/src/Tgstation.Server.Host/Models/Instance.cs @@ -55,7 +55,7 @@ public sealed class Instance : Api.Models.Instance, IApiTransformable Jobs { get; set; } /// - public InstanceResponse ToApi() => new () + public InstanceResponse ToApi() => new() { AutoUpdateInterval = AutoUpdateInterval, ConfigurationType = ConfigurationType, diff --git a/src/Tgstation.Server.Host/Models/Job.cs b/src/Tgstation.Server.Host/Models/Job.cs index 8193402a6a5..674330ee159 100644 --- a/src/Tgstation.Server.Host/Models/Job.cs +++ b/src/Tgstation.Server.Host/Models/Job.cs @@ -42,7 +42,7 @@ public sealed class Job : Api.Models.Internal.Job, IApiTransformableA new ready to be registered with the . public static Job Create(JobCode code, User startedBy, Api.Models.Instance instance, TRight cancelRight) where TRight : Enum - => new ( + => new( code, startedBy, instance, @@ -57,7 +57,7 @@ public static Job Create(JobCode code, User startedBy, Api.Models.Instan /// The used to generate the value of . /// A new ready to be registered with the . public static Job Create(JobCode code, User startedBy, Api.Models.Instance instance) - => new ( + => new( code, startedBy, instance, @@ -109,7 +109,7 @@ public Job(long id) } /// - public JobResponse ToApi() => new () + public JobResponse ToApi() => new() { Id = Id, JobCode = JobCode.Value, diff --git a/src/Tgstation.Server.Host/Models/UserGroup.cs b/src/Tgstation.Server.Host/Models/UserGroup.cs index 11329e9397d..63f351c3299 100644 --- a/src/Tgstation.Server.Host/Models/UserGroup.cs +++ b/src/Tgstation.Server.Host/Models/UserGroup.cs @@ -28,7 +28,7 @@ public sealed class UserGroup : NamedEntity, IApiTransformable /// If should be populated. /// A new . - public UserGroupResponse ToApi(bool showUsers) => new () + public UserGroupResponse ToApi(bool showUsers) => new() { Id = Id, Name = Name, diff --git a/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs index ccb4d7972a5..3195ec9dcf3 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs @@ -17,10 +17,10 @@ sealed class DiscordOAuthValidator : GenericOAuthValidator public override OAuthProvider Provider => OAuthProvider.Discord; /// - protected override Uri TokenUrl => new ("https://discord.com/api/oauth2/token"); + protected override Uri TokenUrl => new("https://discord.com/api/oauth2/token"); /// - protected override Uri UserInformationUrl => new ("https://discord.com/api/users/@me"); + protected override Uri UserInformationUrl => new("https://discord.com/api/users/@me"); /// /// Initializes a new instance of the class. @@ -37,7 +37,7 @@ public DiscordOAuthValidator( } /// - protected override OAuthTokenRequest CreateTokenRequest(string code) => new (OAuthConfiguration, code, "identify"); + protected override OAuthTokenRequest CreateTokenRequest(string code) => new(OAuthConfiguration, code, "identify"); /// protected override string DecodeTokenPayload(dynamic responseJson) => responseJson.access_token; diff --git a/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs index 8606d0921d5..668a96240ff 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs @@ -55,7 +55,7 @@ abstract class GenericOAuthValidator : IOAuthValidator /// Gets that should be used. /// /// A new . - protected static JsonSerializerSettings SerializerSettings() => new () + protected static JsonSerializerSettings SerializerSettings() => new() { ContractResolver = new DefaultContractResolver { @@ -141,7 +141,7 @@ public async ValueTask ValidateResponseCode(string code, CancellationTok /// public OAuthProviderInfo GetProviderInfo() - => new () + => new() { ClientId = OAuthConfiguration.ClientId, RedirectUri = OAuthConfiguration.RedirectUrl, diff --git a/src/Tgstation.Server.Host/Security/OAuth/GitHubOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/GitHubOAuthValidator.cs index f53fe8137c1..567887b06f4 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/GitHubOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/GitHubOAuthValidator.cs @@ -85,7 +85,7 @@ public async ValueTask ValidateResponseCode(string code, CancellationTok /// public OAuthProviderInfo GetProviderInfo() - => new () + => new() { ClientId = oAuthConfiguration.ClientId, RedirectUri = oAuthConfiguration.RedirectUrl, diff --git a/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs index 54d6883e3de..a0c8cdd0e2a 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs @@ -17,10 +17,10 @@ sealed class InvisionCommunityOAuthValidator : GenericOAuthValidator public override OAuthProvider Provider => OAuthProvider.InvisionCommunity; /// - protected override Uri TokenUrl => new ($"{OAuthConfiguration.ServerUrl}/oauth/token/"); // This needs the trailing slash or it doesnt get the token. Do not remove. + protected override Uri TokenUrl => new($"{OAuthConfiguration.ServerUrl}/oauth/token/"); // This needs the trailing slash or it doesnt get the token. Do not remove. /// - protected override Uri UserInformationUrl => new ($"{OAuthConfiguration.ServerUrl}/api/core/me"); + protected override Uri UserInformationUrl => new($"{OAuthConfiguration.ServerUrl}/api/core/me"); /// /// Initializes a new instance of the class. @@ -37,7 +37,7 @@ public InvisionCommunityOAuthValidator( } /// - protected override OAuthTokenRequest CreateTokenRequest(string code) => new (OAuthConfiguration, code, "profile"); + protected override OAuthTokenRequest CreateTokenRequest(string code) => new(OAuthConfiguration, code, "profile"); /// protected override string DecodeTokenPayload(dynamic responseJson) => responseJson.access_token; diff --git a/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs index 03b3ea87325..f4e61b4b5ce 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs @@ -17,10 +17,10 @@ sealed class KeycloakOAuthValidator : GenericOAuthValidator public override OAuthProvider Provider => OAuthProvider.Keycloak; /// - protected override Uri TokenUrl => new ($"{BaseProtocolPath}/token"); + protected override Uri TokenUrl => new($"{BaseProtocolPath}/token"); /// - protected override Uri UserInformationUrl => new ($"{BaseProtocolPath}/userinfo"); + protected override Uri UserInformationUrl => new($"{BaseProtocolPath}/userinfo"); /// /// Base path to the server's OAuth endpoint. @@ -42,7 +42,7 @@ public KeycloakOAuthValidator( } /// - protected override OAuthTokenRequest CreateTokenRequest(string code) => new (OAuthConfiguration, code, "openid"); + protected override OAuthTokenRequest CreateTokenRequest(string code) => new(OAuthConfiguration, code, "openid"); /// protected override string DecodeTokenPayload(dynamic responseJson) => responseJson.access_token; diff --git a/src/Tgstation.Server.Host/Security/OAuth/TGForumsOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/TGForumsOAuthValidator.cs index a65b8346a4f..c81a54ec738 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/TGForumsOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/TGForumsOAuthValidator.cs @@ -17,10 +17,10 @@ sealed class TGForumsOAuthValidator : GenericOAuthValidator public override OAuthProvider Provider => OAuthProvider.TGForums; /// - protected override Uri TokenUrl => new ("https://tgstation13.org/phpBB/app.php/tgapi/oauth/token"); + protected override Uri TokenUrl => new("https://tgstation13.org/phpBB/app.php/tgapi/oauth/token"); /// - protected override Uri UserInformationUrl => new ("https://tgstation13.org/phpBB/app.php/tgapi/user/me"); + protected override Uri UserInformationUrl => new("https://tgstation13.org/phpBB/app.php/tgapi/user/me"); /// /// Initializes a new instance of the class. @@ -46,6 +46,6 @@ public TGForumsOAuthValidator( protected override string DecodeUserInformationPayload(dynamic responseJson) => responseJson.phpbb_username; /// - protected override OAuthTokenRequest CreateTokenRequest(string code) => new (OAuthConfiguration, code, "user"); + protected override OAuthTokenRequest CreateTokenRequest(string code) => new(OAuthConfiguration, code, "user"); } } diff --git a/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs b/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs index f5485cc2805..988c60243ef 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs @@ -66,7 +66,7 @@ static class SwarmConstants /// static SwarmConstants() { - SerializerSettings = new () + SerializerSettings = new() { ContractResolver = new DefaultContractResolver { diff --git a/src/Tgstation.Server.Host/Swarm/SwarmService.cs b/src/Tgstation.Server.Host/Swarm/SwarmService.cs index ba0a117b582..dc4dfa22515 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmService.cs @@ -109,7 +109,7 @@ public bool ExpectedNumberOfNodesConnected /// /// of s to registration s and when they were created. /// - readonly Dictionary registrationIdsAndTimes; + readonly Dictionary registrationIdsAndTimes; /// /// If the current server is the swarm controller. @@ -193,7 +193,7 @@ public SwarmService( serverHealthCheckCancellationTokenSource = new CancellationTokenSource(); forceHealthCheckTcs = new TaskCompletionSource(); if (swarmController) - registrationIdsAndTimes = new (); + registrationIdsAndTimes = new(); swarmServers = new List { @@ -520,7 +520,7 @@ public bool ValidateRegistration(Guid registrationId) { if (swarmController) lock (swarmServers) - return registrationIdsAndTimes.Values.Any(x => x.Item1 == registrationId); + return registrationIdsAndTimes.Values.Any(x => x.RegistrationId == registrationId); if (registrationId != controllerRegistration) return false; @@ -549,9 +549,9 @@ public async ValueTask RegisterNode(Api.Models.Internal.SwarmServer node, lock (swarmServers) { - if (registrationIdsAndTimes.Any(x => x.Value.Item1 == registrationId)) + if (registrationIdsAndTimes.Any(x => x.Value.RegistrationId == registrationId)) { - var preExistingRegistrationKvp = registrationIdsAndTimes.FirstOrDefault(x => x.Value.Item1 == registrationId); + var preExistingRegistrationKvp = registrationIdsAndTimes.FirstOrDefault(x => x.Value.RegistrationId == registrationId); if (preExistingRegistrationKvp.Key == node.Identifier) { logger.LogWarning("Node {nodeId} has already registered!", node.Identifier); @@ -580,7 +580,7 @@ public async ValueTask RegisterNode(Api.Models.Internal.SwarmServer node, Identifier = node.Identifier, Controller = false, }); - registrationIdsAndTimes.Add(node.Identifier, (registrationId, DateTimeOffset.UtcNow)); + registrationIdsAndTimes.Add(node.Identifier, (RegistrationId: registrationId, DateTimeOffset.UtcNow)); } logger.LogInformation("Registered node {nodeId} ({nodeIP}) with ID {registrationId}", node.Identifier, node.Address, registrationId); @@ -1139,7 +1139,7 @@ await ValueTaskExtensions.WhenAll( currentSwarmServers .Where(node => !node.Controller && registrationIdsAndTimes.TryGetValue(node.Identifier, out var registrationAndTime) - && registrationAndTime.Item2.AddMinutes(SwarmConstants.ControllerHealthCheckIntervalMinutes) < DateTimeOffset.UtcNow) + && registrationAndTime.RegisteredAt.AddMinutes(SwarmConstants.ControllerHealthCheckIntervalMinutes) < DateTimeOffset.UtcNow) .Select(HealthRequestForServer)); lock (swarmServers) @@ -1390,7 +1390,7 @@ HttpRequestMessage PrepareSwarmRequest( { lock (swarmServers) if (registrationIdsAndTimes.TryGetValue(swarmServer.Identifier, out var registrationIdAndTime)) - request.Headers.Add(SwarmConstants.RegistrationIdHeader, registrationIdAndTime.Item1.ToString()); + request.Headers.Add(SwarmConstants.RegistrationIdHeader, registrationIdAndTime.RegistrationId.ToString()); } else if (controllerRegistration.HasValue) request.Headers.Add(SwarmConstants.RegistrationIdHeader, controllerRegistration.Value.ToString()); @@ -1505,14 +1505,14 @@ string NodeIdentifierFromRegistration(Guid registrationId) lock (swarmServers) { - var exists = registrationIdsAndTimes.Any(x => x.Value.Item1 == registrationId); + var exists = registrationIdsAndTimes.Any(x => x.Value.RegistrationId == registrationId); if (!exists) { logger.LogWarning("A node that was to be looked up ({registrationId}) disappeared from our records!", registrationId); return null; } - return registrationIdsAndTimes.First(x => x.Value.Item1 == registrationId).Key; + return registrationIdsAndTimes.First(x => x.Value.RegistrationId == registrationId).Key; } } } diff --git a/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs b/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs index 34d2a9a9402..88d1a3a627b 100644 --- a/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs +++ b/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs @@ -26,7 +26,7 @@ sealed class AssemblyInformationProvider : IAssemblyInformationProvider public string VersionString { get; } /// - public ProductInfoHeaderValue ProductInfoHeaderValue => new ( + public ProductInfoHeaderValue ProductInfoHeaderValue => new( VersionPrefix, Version.ToString()); diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index abe50636843..7a00b31d10e 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -17,7 +17,7 @@ sealed class ProcessExecutor : IProcessExecutor /// /// for . /// - static readonly ReaderWriterLockSlim ExclusiveProcessLaunchLock = new (); + static readonly ReaderWriterLockSlim ExclusiveProcessLaunchLock = new(); /// /// The for the . diff --git a/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs b/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs index c30f107ac36..48924155719 100644 --- a/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs +++ b/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs @@ -74,7 +74,7 @@ static List GetAllChildHandles(IntPtr mainWindow) try { var pointerChildHandlesList = GCHandle.ToIntPtr(gcChildhandlesList); - NativeMethods.EnumWindowProc childProc = new (EnumWindow); + NativeMethods.EnumWindowProc childProc = new(EnumWindow); NativeMethods.EnumChildWindows(mainWindow, childProc, pointerChildHandlesList); } finally @@ -113,11 +113,12 @@ public void RegisterProcess(IProcess process) process.Lifetime.ContinueWith( x => - { - logger.LogTrace("Unregistering process {0}...", process.Id); - lock (registeredProcesses) - registeredProcesses.Remove(process); - }, TaskScheduler.Current); + { + logger.LogTrace("Unregistering process {pid}...", process.Id); + lock (registeredProcesses) + registeredProcesses.Remove(process); + }, + TaskScheduler.Current); } /// diff --git a/src/Tgstation.Server.Host/Transfer/FileTransferService.cs b/src/Tgstation.Server.Host/Transfer/FileTransferService.cs index 263bd2ba9c3..fc0201b48dd 100644 --- a/src/Tgstation.Server.Host/Transfer/FileTransferService.cs +++ b/src/Tgstation.Server.Host/Transfer/FileTransferService.cs @@ -240,7 +240,7 @@ public async ValueTask SetUploadStream(FileTicketResponse /// Creates a new . /// /// A new . - FileTicketResponse CreateTicket() => new () + FileTicketResponse CreateTicket() => new() { FileTicket = cryptographySuite.GetSecureString(), }; diff --git a/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs b/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs index 7595a70a431..38fb72ffd68 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs @@ -43,7 +43,7 @@ sealed class GitHubClientFactory : IGitHubClientFactory /// /// Cache of created s and last used times, keyed by access token. /// - readonly Dictionary clientCache; + readonly Dictionary clientCache; /// /// Initializes a new instance of the class. @@ -105,15 +105,15 @@ GitHubClient GetOrCreateClient(string accessToken) if (accessToken != null) client.Credentials = new Credentials(accessToken); - clientCache.Add(cacheKey, (client, now)); + clientCache.Add(cacheKey, (Client: client, LastUsed: now)); lastUsed = null; } else { logger.LogTrace("Cache hit for GitHubClient"); - client = tuple.Item1; - lastUsed = tuple.Item2; - tuple.Item2 = now; + client = tuple.Client; + lastUsed = tuple.LastUsed; + tuple.LastUsed = now; } // Prune the cache @@ -125,7 +125,7 @@ GitHubClient GetOrCreateClient(string accessToken) continue; // save the hash lookup tuple = clientCache[key]; - if (tuple.Item2 <= purgeAfter) + if (tuple.LastUsed <= purgeAfter) { clientCache.Remove(key); ++purgeCount; diff --git a/src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs b/src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs index 8ff53440a68..efa08d13bba 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs @@ -58,7 +58,7 @@ public IAuthenticatedGitHubService CreateService(string accessToken) /// The for the . /// A new . GitHubService CreateServiceImpl(IGitHubClient gitHubClient) - => new ( + => new( gitHubClient, loggerFactory.CreateLogger(), updatesConfiguration); From bc701d288ad27f0fd6b79dddfa6c67c2ed6ab425 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 17:10:06 -0500 Subject: [PATCH 202/717] Enable NRT with global opt-out We will phase this in gradually --- src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs | 4 +++- .../Components/Chat/ChannelRepresentation.cs | 2 ++ src/Tgstation.Server.Host/Components/Chat/ChatManager.cs | 2 ++ .../Components/Chat/ChatManagerFactory.cs | 2 ++ .../Components/Chat/ChatTrackingContext.cs | 2 ++ src/Tgstation.Server.Host/Components/Chat/ChatUser.cs | 2 ++ .../Components/Chat/Commands/CommandFactory.cs | 2 ++ .../Components/Chat/Commands/CustomCommand.cs | 2 ++ .../Components/Chat/Commands/EngineCommand.cs | 2 ++ .../Components/Chat/Commands/ICommand.cs | 2 ++ .../Components/Chat/Commands/ICommandFactory.cs | 2 ++ .../Components/Chat/Commands/KekCommand.cs | 2 ++ .../Components/Chat/Commands/PullRequestsCommand.cs | 2 ++ .../Components/Chat/Commands/RevisionCommand.cs | 2 ++ .../Components/Chat/Commands/VersionCommand.cs | 2 ++ src/Tgstation.Server.Host/Components/Chat/IChannelSink.cs | 2 ++ src/Tgstation.Server.Host/Components/Chat/IChatManager.cs | 2 ++ .../Components/Chat/IChatManagerFactory.cs | 2 ++ .../Components/Chat/IChatTrackingContext.cs | 2 ++ .../Components/Chat/ICustomCommandHandler.cs | 2 ++ .../Components/Chat/Providers/DiscordForwardingResponder.cs | 2 ++ .../Components/Chat/Providers/DiscordMessage.cs | 2 ++ .../Components/Chat/Providers/DiscordProvider.cs | 2 ++ .../Components/Chat/Providers/IDiscordResponders.cs | 2 ++ .../Components/Chat/Providers/IProvider.cs | 2 ++ .../Components/Chat/Providers/IProviderFactory.cs | 2 ++ .../Components/Chat/Providers/IrcProvider.cs | 2 ++ .../Components/Chat/Providers/Message.cs | 4 +++- .../Components/Chat/Providers/Provider.cs | 2 ++ .../Components/Chat/Providers/ProviderFactory.cs | 2 ++ src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs | 2 ++ .../Components/Deployment/DmbProvider.cs | 2 ++ .../Components/Deployment/DmbProviderBase.cs | 2 ++ src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs | 2 ++ .../Components/Deployment/HardLinkDmbProvider.cs | 2 ++ .../Components/Deployment/ICompileJobSink.cs | 2 ++ .../Components/Deployment/IDmbFactory.cs | 2 ++ .../Components/Deployment/IDmbProvider.cs | 2 ++ .../Components/Deployment/IDreamMaker.cs | 2 ++ .../Components/Deployment/ILatestCompileJobProvider.cs | 2 ++ .../Deployment/Remote/BaseRemoteDeploymentManager.cs | 2 ++ .../Deployment/Remote/GitHubRemoteDeploymentManager.cs | 2 ++ .../Deployment/Remote/GitLabRemoteDeploymentManager.cs | 2 ++ .../Components/Deployment/Remote/IRemoteDeploymentManager.cs | 2 ++ .../Deployment/Remote/IRemoteDeploymentManagerFactory.cs | 2 ++ .../Deployment/Remote/NoOpRemoteDeploymentManager.cs | 2 ++ .../Deployment/Remote/RemoteDeploymentManagerFactory.cs | 2 ++ .../Components/Deployment/SwappableDmbProvider.cs | 2 ++ .../Components/Deployment/SymlinkDmbProvider.cs | 2 ++ .../Components/Deployment/TemporaryDmbProvider.cs | 2 ++ .../Components/Engine/ByondInstallation.cs | 2 ++ .../Components/Engine/ByondInstallerBase.cs | 2 ++ .../Components/Engine/DelegatingEngineInstaller.cs | 2 ++ .../Components/Engine/EngineExecutableLock.cs | 2 ++ .../Components/Engine/EngineInstallationBase.cs | 2 ++ .../Components/Engine/EngineInstallerBase.cs | 2 ++ src/Tgstation.Server.Host/Components/Engine/EngineManager.cs | 2 ++ .../Components/Engine/IEngineExecutableLock.cs | 2 ++ .../Components/Engine/IEngineInstallation.cs | 2 ++ .../Components/Engine/IEngineInstallationData.cs | 2 ++ .../Components/Engine/IEngineInstaller.cs | 2 ++ src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs | 2 ++ .../Components/Engine/OpenDreamInstallation.cs | 2 ++ .../Components/Engine/OpenDreamInstaller.cs | 2 ++ .../Components/Engine/PosixByondInstaller.cs | 2 ++ .../Components/Engine/RepositoryEngineInstallationData.cs | 2 ++ .../Components/Engine/WindowsByondInstaller.cs | 2 ++ .../Components/Engine/WindowsOpenDreamInstaller.cs | 2 ++ .../Components/Engine/ZipStreamEngineInstallationData.cs | 2 ++ src/Tgstation.Server.Host/Components/Events/EventConsumer.cs | 2 ++ .../Components/Events/EventScriptAttribute.cs | 2 ++ src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs | 2 ++ .../Components/Events/NoopEventConsumer.cs | 2 ++ src/Tgstation.Server.Host/Components/IComponentService.cs | 2 ++ src/Tgstation.Server.Host/Components/IInstance.cs | 2 ++ src/Tgstation.Server.Host/Components/IInstanceCore.cs | 2 ++ src/Tgstation.Server.Host/Components/IInstanceFactory.cs | 2 ++ src/Tgstation.Server.Host/Components/IInstanceManager.cs | 2 ++ src/Tgstation.Server.Host/Components/IInstanceOperations.cs | 2 ++ src/Tgstation.Server.Host/Components/IInstanceReference.cs | 2 ++ src/Tgstation.Server.Host/Components/IRenameNotifyee.cs | 2 ++ src/Tgstation.Server.Host/Components/Instance.cs | 2 ++ src/Tgstation.Server.Host/Components/InstanceFactory.cs | 2 ++ src/Tgstation.Server.Host/Components/InstanceManager.cs | 2 ++ src/Tgstation.Server.Host/Components/InstanceWrapper.cs | 2 ++ .../Components/Interop/Bridge/BridgeParameters.cs | 2 ++ .../Components/Interop/Bridge/BridgeRegistration.cs | 2 ++ .../Components/Interop/Bridge/BridgeResponse.cs | 2 ++ .../Components/Interop/Bridge/IBridgeDispatcher.cs | 2 ++ .../Components/Interop/Bridge/IBridgeRegistration.cs | 2 ++ .../Components/Interop/Bridge/RuntimeInformation.cs | 2 ++ .../Components/Interop/Bridge/TestMergeInformation.cs | 2 ++ src/Tgstation.Server.Host/Components/Interop/ChatEmbed.cs | 2 ++ .../Components/Interop/ChatEmbedAuthor.cs | 4 +++- .../Components/Interop/ChatEmbedField.cs | 4 +++- .../Components/Interop/ChatEmbedFooter.cs | 4 +++- .../Components/Interop/ChatEmbedMedia.cs | 4 +++- .../Components/Interop/ChatEmbedProvider.cs | 4 +++- src/Tgstation.Server.Host/Components/Interop/ChatMessage.cs | 2 ++ src/Tgstation.Server.Host/Components/Interop/ChatUpdate.cs | 2 ++ src/Tgstation.Server.Host/Components/Interop/ChunkData.cs | 4 +++- src/Tgstation.Server.Host/Components/Interop/Chunker.cs | 2 ++ .../Components/Interop/DMApiConstants.cs | 2 ++ .../Components/Interop/DMApiParameters.cs | 2 ++ src/Tgstation.Server.Host/Components/Interop/DMApiResponse.cs | 4 +++- .../Components/Interop/IMissingPayloadsCommunication.cs | 2 ++ .../Components/Interop/MessageContent.cs | 4 +++- .../Components/Interop/Topic/ChatCommand.cs | 2 ++ .../Components/Interop/Topic/ChunkedTopicParameters.cs | 2 ++ .../Components/Interop/Topic/EventNotification.cs | 2 ++ .../Components/Interop/Topic/TopicCommandType.cs | 2 ++ .../Components/Interop/Topic/TopicParameters.cs | 2 ++ .../Components/Interop/Topic/TopicResponse.cs | 2 ++ .../Components/Repository/DefaultGitRemoteFeatures.cs | 2 ++ .../Components/Repository/GitHubRemoteFeatures.cs | 2 ++ .../Components/Repository/GitLabRemoteFeatures.cs | 2 ++ .../Components/Repository/GitRemoteFeaturesBase.cs | 2 ++ .../Components/Repository/GitRemoteFeaturesFactory.cs | 2 ++ .../Components/Repository/ICredentialsProvider.cs | 2 ++ .../Components/Repository/IGitRemoteAdditionalInformation.cs | 2 ++ .../Components/Repository/IGitRemoteFeaturesFactory.cs | 2 ++ .../Components/Repository/ILibGit2Commands.cs | 2 ++ .../Components/Repository/ILibGit2RepositoryFactory.cs | 2 ++ .../Components/Repository/IRepository.cs | 2 ++ .../Components/Repository/IRepositoryManager.cs | 2 ++ .../Components/Repository/IRepositoryManagerFactory.cs | 2 ++ .../Components/Repository/LibGit2Commands.cs | 2 ++ .../Components/Repository/LibGit2RepositoryFactory.cs | 2 ++ src/Tgstation.Server.Host/Components/Repository/Repository.cs | 2 ++ .../Components/Repository/RepositoryManager.cs | 2 ++ .../Components/Repository/RepositoryUpdateService.cs | 2 ++ .../Components/Repository/RepostoryManagerFactory.cs | 2 ++ .../Components/Repository/TestMergeResult.cs | 2 ++ .../Components/Session/CombinedTopicResponse.cs | 2 ++ .../Components/Session/ISessionController.cs | 2 ++ .../Components/Session/ISessionControllerFactory.cs | 2 ++ .../Components/Session/ISessionPersistor.cs | 2 ++ .../Components/Session/ITopicClientFactory.cs | 2 ++ src/Tgstation.Server.Host/Components/Session/LaunchResult.cs | 2 ++ .../Components/Session/ReattachInformation.cs | 2 ++ .../Components/Session/SessionController.cs | 2 ++ .../Components/Session/SessionControllerFactory.cs | 2 ++ .../Components/Session/SessionPersistor.cs | 2 ++ .../Components/Session/TopicClientFactory.cs | 2 ++ .../Components/StaticFiles/Configuration.cs | 2 ++ .../Components/StaticFiles/IConfiguration.cs | 2 ++ .../Components/Watchdog/AdvancedWatchdog.cs | 2 ++ .../Components/Watchdog/BasicWatchdog.cs | 2 ++ src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs | 2 ++ .../Components/Watchdog/IWatchdogFactory.cs | 2 ++ .../Components/Watchdog/PosixWatchdog.cs | 2 ++ .../Components/Watchdog/PosixWatchdogFactory.cs | 2 ++ src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs | 2 ++ .../Components/Watchdog/WatchdogFactory.cs | 2 ++ .../Components/Watchdog/WindowsWatchdog.cs | 2 ++ .../Components/Watchdog/WindowsWatchdogFactory.cs | 2 ++ .../Configuration/ControlPanelConfiguration.cs | 2 ++ .../Configuration/DatabaseConfiguration.cs | 2 ++ .../Configuration/ElasticsearchConfiguration.cs | 2 ++ .../Configuration/FileLoggingConfiguration.cs | 2 ++ .../Configuration/GeneralConfiguration.cs | 2 ++ .../Configuration/InternalConfiguration.cs | 4 +++- src/Tgstation.Server.Host/Configuration/OAuthConfiguration.cs | 2 ++ .../Configuration/OAuthConfigurationBase.cs | 2 ++ .../Configuration/SecurityConfiguration.cs | 2 ++ src/Tgstation.Server.Host/Configuration/SwarmConfiguration.cs | 2 ++ .../Configuration/UpdatesConfiguration.cs | 2 ++ .../Controllers/AdministrationController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/ApiController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/ApiControllerBase.cs | 2 ++ src/Tgstation.Server.Host/Controllers/ApiRootController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/BridgeController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/ChatController.cs | 2 ++ .../Controllers/ComponentInterfacingController.cs | 2 ++ .../Controllers/ConfigurationController.cs | 2 ++ .../Controllers/ControlPanelController.cs | 2 ++ .../Controllers/DreamDaemonController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/DreamMakerController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/EngineController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/InstanceController.cs | 2 ++ .../Controllers/InstancePermissionSetController.cs | 2 ++ .../Controllers/InstanceRequiredController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/JobController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/RepositoryController.cs | 2 ++ .../Controllers/Results/LimitedStreamResult.cs | 2 ++ .../Controllers/Results/LimitedStreamResultExecutor.cs | 2 ++ .../Controllers/Results/PaginatableResult.cs | 2 ++ src/Tgstation.Server.Host/Controllers/RootController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/SwarmController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/TransferController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/UserController.cs | 2 ++ src/Tgstation.Server.Host/Controllers/UserGroupController.cs | 2 ++ src/Tgstation.Server.Host/Core/Application.cs | 2 ++ src/Tgstation.Server.Host/Core/CommandPipeManager.cs | 2 ++ src/Tgstation.Server.Host/Core/IRestartHandler.cs | 2 ++ src/Tgstation.Server.Host/Core/IRestartRegistration.cs | 2 ++ src/Tgstation.Server.Host/Core/IServerControl.cs | 2 ++ src/Tgstation.Server.Host/Core/IServerUpdateExecutor.cs | 2 ++ src/Tgstation.Server.Host/Core/IServerUpdateInitiator.cs | 2 ++ src/Tgstation.Server.Host/Core/IServerUpdater.cs | 2 ++ src/Tgstation.Server.Host/Core/RestartRegistration.cs | 2 ++ src/Tgstation.Server.Host/Core/ServerPortProivder.cs | 2 ++ src/Tgstation.Server.Host/Core/ServerUpdateInitiator.cs | 2 ++ src/Tgstation.Server.Host/Core/ServerUpdateOperation.cs | 2 ++ src/Tgstation.Server.Host/Core/ServerUpdater.cs | 2 ++ src/Tgstation.Server.Host/Database/DatabaseCollection.cs | 2 ++ .../Database/DatabaseConnectionFactory.cs | 2 ++ src/Tgstation.Server.Host/Database/DatabaseContext.cs | 2 ++ src/Tgstation.Server.Host/Database/DatabaseContextFactory.cs | 2 ++ src/Tgstation.Server.Host/Database/DatabaseSeeder.cs | 2 ++ .../Database/Design/DesignTimeDbContextFactoryHelpers.cs | 2 ++ .../Database/Design/MySqlDesignTimeDbContextFactory.cs | 2 ++ .../Database/Design/PostgresSqlDesignTimeDbContextFactory.cs | 2 ++ .../Database/Design/SqlServerDesignTimeDbContextFactory.cs | 2 ++ .../Database/Design/SqliteDesignTimeDbContextFactory.cs | 2 ++ src/Tgstation.Server.Host/Database/IDatabaseCollection.cs | 2 ++ .../Database/IDatabaseConnectionFactory.cs | 2 ++ src/Tgstation.Server.Host/Database/IDatabaseContext.cs | 2 ++ src/Tgstation.Server.Host/Database/IDatabaseContextFactory.cs | 2 ++ src/Tgstation.Server.Host/Database/IDatabaseSeeder.cs | 2 ++ src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs | 2 ++ .../Database/PostgresSqlDatabaseContext.cs | 2 ++ .../Database/SqlServerDatabaseContext.cs | 2 ++ src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs | 2 ++ .../Extensions/ApplicationBuilderExtensions.cs | 2 ++ src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs | 2 ++ .../Extensions/ControllerBaseExtensions.cs | 2 ++ .../Extensions/Converters/BoolConverter.cs | 2 ++ .../Extensions/Converters/VersionConverter.cs | 2 ++ .../Extensions/DatabaseCollectionExtensions.cs | 2 ++ .../Extensions/DateTimeOffsetExtensions.cs | 2 ++ .../Extensions/FileTransferStreamHandlerExtensions.cs | 2 ++ .../Extensions/GeneralConfigurationExtensions.cs | 2 ++ src/Tgstation.Server.Host/Extensions/HostBuilderExtensions.cs | 2 ++ .../Extensions/ModelBuilderExtensions.cs | 2 ++ src/Tgstation.Server.Host/Extensions/ResultExtensions.cs | 2 ++ .../Extensions/ServiceCollectionExtensions.cs | 2 ++ src/Tgstation.Server.Host/Extensions/SocketExtensions.cs | 2 ++ src/Tgstation.Server.Host/Extensions/TaskExtensions.cs | 2 ++ .../Extensions/WebHostBuilderExtensions.cs | 2 ++ src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs | 2 ++ src/Tgstation.Server.Host/IO/Console.cs | 2 ++ src/Tgstation.Server.Host/IO/DefaultIOManager.cs | 2 ++ src/Tgstation.Server.Host/IO/FileDownloader.cs | 2 ++ src/Tgstation.Server.Host/IO/IConsole.cs | 2 ++ src/Tgstation.Server.Host/IO/IFileDownloader.cs | 2 ++ src/Tgstation.Server.Host/IO/IFileStreamProvider.cs | 2 ++ src/Tgstation.Server.Host/IO/IFilesystemLinkFactory.cs | 2 ++ src/Tgstation.Server.Host/IO/IIOManager.cs | 2 ++ src/Tgstation.Server.Host/IO/ISeekableFileStreamProvider.cs | 2 ++ src/Tgstation.Server.Host/IO/ISynchronousIOManager.cs | 2 ++ src/Tgstation.Server.Host/IO/PosixFilesystemLinkFactory.cs | 2 ++ src/Tgstation.Server.Host/IO/PosixPostWriteHandler.cs | 2 ++ src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs | 2 ++ src/Tgstation.Server.Host/IO/ResolvingIOManager.cs | 2 ++ src/Tgstation.Server.Host/IO/SynchronousIOManager.cs | 2 ++ src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs | 2 ++ src/Tgstation.Server.Host/IO/WindowsPostWriteHandler.cs | 2 ++ src/Tgstation.Server.Host/IServer.cs | 2 ++ src/Tgstation.Server.Host/IServerFactory.cs | 2 ++ src/Tgstation.Server.Host/Jobs/IJobManager.cs | 2 ++ src/Tgstation.Server.Host/Jobs/IJobService.cs | 2 ++ src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs | 2 ++ src/Tgstation.Server.Host/Jobs/JobException.cs | 2 ++ src/Tgstation.Server.Host/Jobs/JobHandler.cs | 2 ++ src/Tgstation.Server.Host/Jobs/JobProgressReporter.cs | 2 ++ src/Tgstation.Server.Host/Jobs/JobService.cs | 2 ++ src/Tgstation.Server.Host/Jobs/JobsHub.cs | 2 ++ src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs | 2 ++ src/Tgstation.Server.Host/Models/ChatBot.cs | 2 ++ src/Tgstation.Server.Host/Models/ChatChannel.cs | 2 ++ src/Tgstation.Server.Host/Models/CompileJob.cs | 2 ++ src/Tgstation.Server.Host/Models/DreamDaemonSettings.cs | 2 ++ src/Tgstation.Server.Host/Models/DreamMakerSettings.cs | 2 ++ src/Tgstation.Server.Host/Models/Instance.cs | 2 ++ src/Tgstation.Server.Host/Models/InstancePermissionSet.cs | 2 ++ src/Tgstation.Server.Host/Models/Job.cs | 2 ++ src/Tgstation.Server.Host/Models/OAuthConnection.cs | 4 +++- src/Tgstation.Server.Host/Models/PermissionSet.cs | 2 ++ src/Tgstation.Server.Host/Models/ReattachInformation.cs | 2 ++ src/Tgstation.Server.Host/Models/ReattachInformationBase.cs | 2 ++ src/Tgstation.Server.Host/Models/RepositorySettings.cs | 2 ++ src/Tgstation.Server.Host/Models/RevInfoTestMerge.cs | 2 ++ src/Tgstation.Server.Host/Models/RevisionInformation.cs | 2 ++ src/Tgstation.Server.Host/Models/TestMerge.cs | 2 ++ src/Tgstation.Server.Host/Models/User.cs | 2 ++ src/Tgstation.Server.Host/Models/UserGroup.cs | 2 ++ src/Tgstation.Server.Host/Program.cs | 2 ++ .../Properties/MasterVersionsAttribute.cs | 2 ++ src/Tgstation.Server.Host/Security/AuthenticationContext.cs | 2 ++ .../Security/AuthenticationContextAuthorizationFilter.cs | 2 ++ .../Security/AuthenticationContextClaimsTransformation.cs | 2 ++ .../Security/AuthenticationContextFactory.cs | 2 ++ .../Security/AuthorizationContextHubFilter.cs | 2 ++ src/Tgstation.Server.Host/Security/CryptographySuite.cs | 2 ++ src/Tgstation.Server.Host/Security/IAuthenticationContext.cs | 2 ++ .../Security/IAuthenticationContextFactory.cs | 2 ++ src/Tgstation.Server.Host/Security/ICryptographySuite.cs | 2 ++ src/Tgstation.Server.Host/Security/IIdentityCache.cs | 2 ++ .../Security/IPermissionsUpdateNotifyee.cs | 2 ++ src/Tgstation.Server.Host/Security/ISystemIdentity.cs | 2 ++ src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs | 2 ++ src/Tgstation.Server.Host/Security/ITokenFactory.cs | 2 ++ src/Tgstation.Server.Host/Security/IdentityCache.cs | 2 ++ src/Tgstation.Server.Host/Security/IdentityCacheObject.cs | 2 ++ .../Security/OAuth/DiscordOAuthValidator.cs | 2 ++ .../Security/OAuth/GenericOAuthValidator.cs | 2 ++ .../Security/OAuth/GitHubOAuthValidator.cs | 2 ++ src/Tgstation.Server.Host/Security/OAuth/IOAuthProviders.cs | 2 ++ src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs | 2 ++ .../Security/OAuth/InvisionCommunityOAuthValidator.cs | 2 ++ .../Security/OAuth/KeycloakOAuthValidator.cs | 2 ++ src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs | 2 ++ src/Tgstation.Server.Host/Security/OAuth/OAuthTokenRequest.cs | 2 ++ .../Security/OAuth/TGForumsOAuthValidator.cs | 2 ++ src/Tgstation.Server.Host/Security/PosixSystemIdentity.cs | 2 ++ .../Security/PosixSystemIdentityFactory.cs | 2 ++ src/Tgstation.Server.Host/Security/TgsAuthorizeAttribute.cs | 2 ++ src/Tgstation.Server.Host/Security/TokenFactory.cs | 2 ++ src/Tgstation.Server.Host/Security/WindowsSystemIdentity.cs | 2 ++ .../Security/WindowsSystemIdentityFactory.cs | 2 ++ src/Tgstation.Server.Host/Server.cs | 2 ++ src/Tgstation.Server.Host/ServerFactory.cs | 2 ++ src/Tgstation.Server.Host/Setup/IPostSetupServices.cs | 2 ++ .../Setup/IPostSetupServices{TLoggerType}.cs | 2 ++ src/Tgstation.Server.Host/Setup/PostSetupServices.cs | 2 ++ src/Tgstation.Server.Host/Setup/SetupApplication.cs | 2 ++ src/Tgstation.Server.Host/Setup/SetupWizard.cs | 2 ++ src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs | 2 ++ src/Tgstation.Server.Host/Swarm/ISwarmService.cs | 2 ++ src/Tgstation.Server.Host/Swarm/ISwarmServiceController.cs | 2 ++ src/Tgstation.Server.Host/Swarm/ISwarmUpdateAborter.cs | 2 ++ src/Tgstation.Server.Host/Swarm/SwarmConstants.cs | 2 ++ src/Tgstation.Server.Host/Swarm/SwarmRegistrationRequest.cs | 2 ++ src/Tgstation.Server.Host/Swarm/SwarmServersUpdateRequest.cs | 2 ++ src/Tgstation.Server.Host/Swarm/SwarmService.cs | 2 ++ src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs | 2 ++ src/Tgstation.Server.Host/Swarm/SwarmUpdateRequest.cs | 2 ++ .../System/AssemblyInformationProvider.cs | 2 ++ .../System/IAssemblyInformationProvider.cs | 2 ++ src/Tgstation.Server.Host/System/IPlatformIdentifier.cs | 2 ++ src/Tgstation.Server.Host/System/IProcess.cs | 2 ++ src/Tgstation.Server.Host/System/IProcessBase.cs | 2 ++ src/Tgstation.Server.Host/System/IProcessExecutor.cs | 4 +++- src/Tgstation.Server.Host/System/IProcessFeatures.cs | 2 ++ src/Tgstation.Server.Host/System/NativeMethods.cs | 2 ++ src/Tgstation.Server.Host/System/PlatformIdentifier.cs | 2 ++ src/Tgstation.Server.Host/System/PosixProcessFeatures.cs | 2 ++ src/Tgstation.Server.Host/System/PosixSignalHandler.cs | 2 ++ src/Tgstation.Server.Host/System/Process.cs | 2 ++ src/Tgstation.Server.Host/System/ProcessExecutor.cs | 2 ++ .../System/ProgramShutdownTokenSource.cs | 2 ++ src/Tgstation.Server.Host/System/SystemDManager.cs | 2 ++ src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs | 2 ++ .../System/WindowsNetworkPromptReaper.cs | 2 ++ src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs | 2 ++ src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 1 + src/Tgstation.Server.Host/Transfer/FileDownloadProvider.cs | 2 ++ src/Tgstation.Server.Host/Transfer/FileTransferService.cs | 2 ++ src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs | 2 ++ .../Transfer/IFileTransferStreamHandler.cs | 2 ++ .../Transfer/IFileTransferTicketProvider.cs | 2 ++ src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs | 2 ++ src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs | 2 ++ src/Tgstation.Server.Host/Utils/ApiHeadersProvider.cs | 2 ++ src/Tgstation.Server.Host/Utils/AsyncDelayer.cs | 2 ++ src/Tgstation.Server.Host/Utils/FifoSemaphore.cs | 2 ++ src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs | 2 ++ src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs | 2 ++ .../Utils/GitHub/GitHubServiceFactory.cs | 2 ++ .../Utils/GitHub/IAuthenticatedGitHubService.cs | 2 ++ .../Utils/GitHub/IGitHubClientFactory.cs | 2 ++ src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs | 2 ++ src/Tgstation.Server.Host/Utils/IApiHeadersProvider.cs | 2 ++ src/Tgstation.Server.Host/Utils/IAsyncDelayer.cs | 2 ++ src/Tgstation.Server.Host/Utils/IPortAllocator.cs | 2 ++ .../Utils/OpenApiEnumVarNamesExtension.cs | 2 ++ src/Tgstation.Server.Host/Utils/PortAllocator.cs | 2 ++ src/Tgstation.Server.Host/Utils/ReferenceCounter.cs | 2 ++ src/Tgstation.Server.Host/Utils/ReferenceCountingContainer.cs | 2 ++ src/Tgstation.Server.Host/Utils/SemaphoreSlimContext.cs | 2 ++ .../Utils/SignalR/ComprehensiveHubContext.cs | 2 ++ .../Utils/SignalR/ConnectionMappingHub.cs | 2 ++ .../Utils/SignalR/IConnectionMappedHubContext.cs | 2 ++ .../Utils/SignalR/IHubConnectionMapper.cs | 2 ++ src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs | 2 ++ 386 files changed, 784 insertions(+), 13 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs b/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs index d7430d7c69e..8773e402a96 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.Components.Chat +#nullable disable + +namespace Tgstation.Server.Host.Components.Chat { /// /// Represents a mapping of a . diff --git a/src/Tgstation.Server.Host/Components/Chat/ChannelRepresentation.cs b/src/Tgstation.Server.Host/Components/Chat/ChannelRepresentation.cs index a24f416ec11..aed43e08174 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChannelRepresentation.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChannelRepresentation.cs @@ -3,6 +3,8 @@ using Newtonsoft.Json; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index 7e3daa66466..409c6555c24 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -21,6 +21,8 @@ using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManagerFactory.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManagerFactory.cs index 12427da6bef..7e9c09eb423 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManagerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManagerFactory.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Host.Components.Chat.Providers; using Tgstation.Server.Host.Core; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs b/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs index 369ccdeeebe..bf6ab315ed9 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Host.Components.Chat.Commands; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatUser.cs b/src/Tgstation.Server.Host/Components/Chat/ChatUser.cs index 6de07109eac..9660bc6c83b 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatUser.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatUser.cs @@ -3,6 +3,8 @@ using Newtonsoft.Json; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs index d4fda666039..28eecb26286 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Commands { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/CustomCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/CustomCommand.cs index 617b1dba48b..b11d22d5ef4 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/CustomCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/CustomCommand.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Components.Interop; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Commands { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs index 9e92f3f02f1..75a6e79e547 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Watchdog; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Commands { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs index 766f29b6c00..c5d4e3ef3ea 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.Components.Interop; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Commands { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/ICommandFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/ICommandFactory.cs index c3ffa50d74c..1cc91c7ada3 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/ICommandFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/ICommandFactory.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Commands { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/KekCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/KekCommand.cs index a41278ae0aa..f5ef18e1d99 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/KekCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/KekCommand.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.Components.Interop; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Commands { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs index 39a99bcac4e..990b5bdc11c 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs @@ -13,6 +13,8 @@ using Tgstation.Server.Host.Components.Watchdog; using Tgstation.Server.Host.Database; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Commands { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/RevisionCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/RevisionCommand.cs index aceff96435e..60c12f9fc35 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/RevisionCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/RevisionCommand.cs @@ -9,6 +9,8 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Components.Watchdog; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Commands { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/VersionCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/VersionCommand.cs index 60e7f9e9a17..5857f6fea7e 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/VersionCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/VersionCommand.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Commands { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/IChannelSink.cs b/src/Tgstation.Server.Host/Components/Chat/IChannelSink.cs index e9e366902e4..78dbee1d738 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChannelSink.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChannelSink.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs index ae4aefb8fb3..435c867d3eb 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Interop; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/IChatManagerFactory.cs b/src/Tgstation.Server.Host/Components/Chat/IChatManagerFactory.cs index bff29dc9c45..4af42411bee 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChatManagerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChatManagerFactory.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Host.Components.Chat.Commands; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/IChatTrackingContext.cs b/src/Tgstation.Server.Host/Components/Chat/IChatTrackingContext.cs index 37e1da9584b..284c0f5564e 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChatTrackingContext.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChatTrackingContext.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.Components.Chat.Commands; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/ICustomCommandHandler.cs b/src/Tgstation.Server.Host/Components/Chat/ICustomCommandHandler.cs index bf406bb4219..988f3faa2f3 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ICustomCommandHandler.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ICustomCommandHandler.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.Components.Interop; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordForwardingResponder.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordForwardingResponder.cs index 85444cb499b..878ac1bc4c1 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordForwardingResponder.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordForwardingResponder.cs @@ -6,6 +6,8 @@ using Remora.Discord.Gateway.Responders; using Remora.Results; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Providers { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordMessage.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordMessage.cs index b0b3fbb56eb..4d55e31d85e 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordMessage.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordMessage.cs @@ -1,6 +1,8 @@ using Remora.Discord.API.Abstractions.Objects; using Remora.Rest.Core; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Providers { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index bda2228065b..3ee853f36c1 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -33,6 +33,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Providers { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IDiscordResponders.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IDiscordResponders.cs index d0c320fa9e0..3ca8ec9d42e 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IDiscordResponders.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IDiscordResponders.cs @@ -1,6 +1,8 @@ using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.Gateway.Responders; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Providers { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs index 22028aefc77..0fc6beeb299 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Providers { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IProviderFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IProviderFactory.cs index d79e0bb7d5c..fea864ea717 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IProviderFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IProviderFactory.cs @@ -1,5 +1,7 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Providers { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index e4fe37a93e1..b870536fb76 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -19,6 +19,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Providers { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/Message.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/Message.cs index 9510113f62e..f410514b807 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/Message.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/Message.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.Components.Chat.Providers +#nullable disable + +namespace Tgstation.Server.Host.Components.Chat.Providers { /// /// Represents a message received by a . diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs index 7da3b299308..1a036d7ffdc 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs @@ -11,6 +11,8 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Providers { /// diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs index ed3608b92da..9519abcc1c2 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs @@ -10,6 +10,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Chat.Providers { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs index de36092c6b6..3e969409b40 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs @@ -16,6 +16,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs index 37c44d9fab9..359fc615e20 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs index 5f1248463d5..cdc57215ac1 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index 3a8a256fd11..5d994636371 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -25,6 +25,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/HardLinkDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/HardLinkDmbProvider.cs index 568786e3408..99fd9c4bc26 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/HardLinkDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/HardLinkDmbProvider.cs @@ -15,6 +15,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/ICompileJobSink.cs b/src/Tgstation.Server.Host/Components/Deployment/ICompileJobSink.cs index 49d4eae165e..90a0f1596c8 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/ICompileJobSink.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/ICompileJobSink.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs index 6ff04b0a00f..a6c31736770 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs index 820796c3186..20ef72dd331 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Api.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/IDreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/IDreamMaker.cs index 32443080165..b9e8f4e88ad 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/IDreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/IDreamMaker.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/ILatestCompileJobProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/ILatestCompileJobProvider.cs index 38a90c8dc60..d60ac9ad314 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/ILatestCompileJobProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/ILatestCompileJobProvider.cs @@ -1,5 +1,7 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs index db48c659ba5..b06a3f86623 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs @@ -11,6 +11,8 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment.Remote { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs index 751bb336461..493daab039f 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs @@ -17,6 +17,8 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Utils.GitHub; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment.Remote { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs index 2686764cca0..0190d0c9936 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs @@ -14,6 +14,8 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment.Remote { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManager.cs index 42b154ac7ef..de92f3d31bc 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManager.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment.Remote { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManagerFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManagerFactory.cs index b3dce1f69c1..129d5aa35a8 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManagerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManagerFactory.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Api.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment.Remote { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/NoOpRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/NoOpRemoteDeploymentManager.cs index 6751f181849..250b43bddf3 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/NoOpRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/NoOpRemoteDeploymentManager.cs @@ -10,6 +10,8 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment.Remote { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/RemoteDeploymentManagerFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/RemoteDeploymentManagerFactory.cs index 0fdce864cf9..d525d3dffe3 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/RemoteDeploymentManagerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/RemoteDeploymentManagerFactory.cs @@ -9,6 +9,8 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Utils.GitHub; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment.Remote { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs index 75c5a1b6bb1..954fa920bec 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/SymlinkDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/SymlinkDmbProvider.cs index edb570bcb85..a920641d0d1 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/SymlinkDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/SymlinkDmbProvider.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs index 4d528d7ba1e..38c5067c554 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Api.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Deployment { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs index ba730a7c7fa..b1cc0a9d5dd 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index cf20d498a97..96a7df1aa97 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -11,6 +11,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs index 75393af5b77..c9e859f37de 100644 --- a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Jobs; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs index 70614f13e17..02d9bfe4931 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs index fb607d36011..2133bdade40 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs index e281c3f48fc..6e2d5ad3cc9 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index 12051204114..ab767631672 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -16,6 +16,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineExecutableLock.cs index 66031902fbb..5d7bb087f96 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineExecutableLock.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs index f9aecca33b3..861d6ebe90a 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs index b3d8458973c..6385be5a9ed 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs index 23602025849..427ebfe55fc 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Jobs; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs index bc272b1038a..d53d77c53ab 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Jobs; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index 254861e69a6..db3e7a7392d 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index bbd09ed1c1d..feb26e8be5b 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -15,6 +15,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs index cddace53c8c..ed58f07d415 100644 --- a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs @@ -10,6 +10,8 @@ using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs b/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs index 88fbb779117..2c96b6f3113 100644 --- a/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs +++ b/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 0ebf63ff9fe..d119a5350f2 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -15,6 +15,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index 4f42884c7f3..e821f675afd 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -13,6 +13,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs b/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs index 292b7259817..71c26b92ef4 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Components.Engine { /// diff --git a/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs index 81a0d34585d..ae805853fb7 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Host.Components.StaticFiles; using Tgstation.Server.Host.Components.Watchdog; +#nullable disable + namespace Tgstation.Server.Host.Components.Events { /// diff --git a/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs b/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs index ba93d34cf95..fafcd825623 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +#nullable disable + namespace Tgstation.Server.Host.Components.Events { /// diff --git a/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs index 7fddbb8950f..4c2a7be5bd3 100644 --- a/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs +++ b/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Components.Events { /// diff --git a/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs index a8b07e4d7e0..531018f7b55 100644 --- a/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs +++ b/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Components.Events { /// diff --git a/src/Tgstation.Server.Host/Components/IComponentService.cs b/src/Tgstation.Server.Host/Components/IComponentService.cs index b094e0a0929..6ef039f6548 100644 --- a/src/Tgstation.Server.Host/Components/IComponentService.cs +++ b/src/Tgstation.Server.Host/Components/IComponentService.cs @@ -1,5 +1,7 @@ using Microsoft.Extensions.Hosting; +#nullable disable + namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Components/IInstance.cs b/src/Tgstation.Server.Host/Components/IInstance.cs index 9d8c34988e7..b7b75050538 100644 --- a/src/Tgstation.Server.Host/Components/IInstance.cs +++ b/src/Tgstation.Server.Host/Components/IInstance.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Components/IInstanceCore.cs b/src/Tgstation.Server.Host/Components/IInstanceCore.cs index 78bce9e3f31..1fd3a29d454 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceCore.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceCore.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Host.Components.StaticFiles; using Tgstation.Server.Host.Components.Watchdog; +#nullable disable + namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Components/IInstanceFactory.cs b/src/Tgstation.Server.Host/Components/IInstanceFactory.cs index 6258614b5f5..5728f7f632e 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceFactory.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Components/IInstanceManager.cs b/src/Tgstation.Server.Host/Components/IInstanceManager.cs index 3174686efe8..c9439c2bdbe 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceManager.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Host.Components.Interop.Bridge; +#nullable disable + namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Components/IInstanceOperations.cs b/src/Tgstation.Server.Host/Components/IInstanceOperations.cs index 3212d9d6dcf..8d81a1d69c3 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceOperations.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceOperations.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Components/IInstanceReference.cs b/src/Tgstation.Server.Host/Components/IInstanceReference.cs index 55f9379e80c..14a63a76492 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceReference.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceReference.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Components/IRenameNotifyee.cs b/src/Tgstation.Server.Host/Components/IRenameNotifyee.cs index be22158bd9d..5394921314b 100644 --- a/src/Tgstation.Server.Host/Components/IRenameNotifyee.cs +++ b/src/Tgstation.Server.Host/Components/IRenameNotifyee.cs @@ -1,6 +1,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 7176e8f050f..10b0e89cd7a 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -21,6 +21,8 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index a2e9dc6ff59..a9f5878c417 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -25,6 +25,8 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index 0959e9ca018..bf2b5dbba09 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -26,6 +26,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Components/InstanceWrapper.cs b/src/Tgstation.Server.Host/Components/InstanceWrapper.cs index 5c525d98698..21861d17069 100644 --- a/src/Tgstation.Server.Host/Components/InstanceWrapper.cs +++ b/src/Tgstation.Server.Host/Components/InstanceWrapper.cs @@ -10,6 +10,8 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs index c1c9213063c..a1475ed1f92 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Components.Chat.Commands; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Bridge { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeRegistration.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeRegistration.cs index ade7d5adfe8..e209a63aa6a 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeRegistration.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeRegistration.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Bridge { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeResponse.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeResponse.cs index f7f358d6121..27113567b26 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeResponse.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeResponse.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Bridge { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeDispatcher.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeDispatcher.cs index 82de2d66312..166daa4a217 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeDispatcher.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeDispatcher.cs @@ -1,6 +1,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Bridge { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeRegistration.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeRegistration.cs index 189846f0810..50f17cf9120 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeRegistration.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeRegistration.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Bridge { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/RuntimeInformation.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/RuntimeInformation.cs index b7d05b67d79..a24a17a614f 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/RuntimeInformation.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/RuntimeInformation.cs @@ -9,6 +9,8 @@ using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Bridge { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/TestMergeInformation.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/TestMergeInformation.cs index 1270af68cf3..3543f052bbf 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/TestMergeInformation.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/TestMergeInformation.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Api.Models.Internal; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Bridge { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatEmbed.cs b/src/Tgstation.Server.Host/Components/Interop/ChatEmbed.cs index da3518ec2a6..e76c2bcbd87 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatEmbed.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatEmbed.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedAuthor.cs b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedAuthor.cs index b79d38be5b5..97b5d26fd4f 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedAuthor.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedAuthor.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.Components.Interop +#nullable disable + +namespace Tgstation.Server.Host.Components.Interop { /// /// Represents information about a author. diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedField.cs b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedField.cs index 9d3ca0b864c..f5845579920 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedField.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedField.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.Components.Interop +#nullable disable + +namespace Tgstation.Server.Host.Components.Interop { /// /// Represents a field in a . diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedFooter.cs b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedFooter.cs index 0df7a2c5d9c..2105603d92b 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedFooter.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedFooter.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.Components.Interop +#nullable disable + +namespace Tgstation.Server.Host.Components.Interop { /// /// Represents a footer in a . diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedMedia.cs b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedMedia.cs index 1cad4c4349b..ebab7bfa805 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedMedia.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedMedia.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.Components.Interop +#nullable disable + +namespace Tgstation.Server.Host.Components.Interop { /// /// Represents information about a thumbnail in a . diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedProvider.cs b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedProvider.cs index 386a269a7d3..c7a29b039ea 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedProvider.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedProvider.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.Components.Interop +#nullable disable + +namespace Tgstation.Server.Host.Components.Interop { /// /// Represents information about a provider. diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatMessage.cs b/src/Tgstation.Server.Host/Components/Interop/ChatMessage.cs index 3d8900e4276..2178cc1a1d4 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatMessage.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatMessage.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatUpdate.cs b/src/Tgstation.Server.Host/Components/Interop/ChatUpdate.cs index 12e9b408abb..af902de7b60 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatUpdate.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatUpdate.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Components.Chat; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/ChunkData.cs b/src/Tgstation.Server.Host/Components/Interop/ChunkData.cs index ee6122d7649..8c442413c5f 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChunkData.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChunkData.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.Components.Interop +#nullable disable + +namespace Tgstation.Server.Host.Components.Interop { /// /// A packet of a split serialized set of data. diff --git a/src/Tgstation.Server.Host/Components/Interop/Chunker.cs b/src/Tgstation.Server.Host/Components/Interop/Chunker.cs index d6a0c7c024e..ae8341b9420 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Chunker.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Chunker.cs @@ -7,6 +7,8 @@ using Newtonsoft.Json; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs index 2a59892180c..def2cb27e7c 100644 --- a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs +++ b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Host.Extensions.Converters; using Tgstation.Server.Host.Properties; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiParameters.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiParameters.cs index a6faad32928..55954dd38de 100644 --- a/src/Tgstation.Server.Host/Components/Interop/DMApiParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/DMApiParameters.cs @@ -1,5 +1,7 @@ using System.ComponentModel.DataAnnotations; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiResponse.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiResponse.cs index bb1adf4925e..1196d8aa6fa 100644 --- a/src/Tgstation.Server.Host/Components/Interop/DMApiResponse.cs +++ b/src/Tgstation.Server.Host/Components/Interop/DMApiResponse.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.Components.Interop +#nullable disable + +namespace Tgstation.Server.Host.Components.Interop { /// /// Common base for interop responses. diff --git a/src/Tgstation.Server.Host/Components/Interop/IMissingPayloadsCommunication.cs b/src/Tgstation.Server.Host/Components/Interop/IMissingPayloadsCommunication.cs index 392cd7eecb9..77c3ebff3fa 100644 --- a/src/Tgstation.Server.Host/Components/Interop/IMissingPayloadsCommunication.cs +++ b/src/Tgstation.Server.Host/Components/Interop/IMissingPayloadsCommunication.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/MessageContent.cs b/src/Tgstation.Server.Host/Components/Interop/MessageContent.cs index 6d484a411b0..73e29809068 100644 --- a/src/Tgstation.Server.Host/Components/Interop/MessageContent.cs +++ b/src/Tgstation.Server.Host/Components/Interop/MessageContent.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.Components.Interop +#nullable disable + +namespace Tgstation.Server.Host.Components.Interop { /// /// Represents a message to send to a chat provider. diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/ChatCommand.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/ChatCommand.cs index 5f50d6bba81..34aeed50e73 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/ChatCommand.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/ChatCommand.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Host.Components.Chat; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Topic { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/ChunkedTopicParameters.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/ChunkedTopicParameters.cs index 79353a66bb6..99bf573d9bc 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/ChunkedTopicParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/ChunkedTopicParameters.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Topic { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/EventNotification.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/EventNotification.cs index 54a8d496a5a..6977a275547 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/EventNotification.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/EventNotification.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Components.Events; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Topic { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicCommandType.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicCommandType.cs index 286c605d07d..08d8917a660 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicCommandType.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicCommandType.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Topic { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs index 65c060b412d..8674e0679d4 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Components.Session; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Topic { /// diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicResponse.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicResponse.cs index f108aba5432..3b936b514ea 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicResponse.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicResponse.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Host.Components.Chat.Commands; +#nullable disable + namespace Tgstation.Server.Host.Components.Interop.Topic { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/DefaultGitRemoteFeatures.cs b/src/Tgstation.Server.Host/Components/Repository/DefaultGitRemoteFeatures.cs index ead4007720f..c5909b7b840 100644 --- a/src/Tgstation.Server.Host/Components/Repository/DefaultGitRemoteFeatures.cs +++ b/src/Tgstation.Server.Host/Components/Repository/DefaultGitRemoteFeatures.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/GitHubRemoteFeatures.cs b/src/Tgstation.Server.Host/Components/Repository/GitHubRemoteFeatures.cs index 6e5d5c4ec06..2aa9cb33128 100644 --- a/src/Tgstation.Server.Host/Components/Repository/GitHubRemoteFeatures.cs +++ b/src/Tgstation.Server.Host/Components/Repository/GitHubRemoteFeatures.cs @@ -9,6 +9,8 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Utils.GitHub; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs b/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs index def1adbaaf6..1f34ceeacbe 100644 --- a/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs +++ b/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesBase.cs b/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesBase.cs index 1b1c5337afb..b0adfdb2982 100644 --- a/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesBase.cs +++ b/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesBase.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesFactory.cs b/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesFactory.cs index ab5dcb45ec9..2c7c222071c 100644 --- a/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesFactory.cs +++ b/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesFactory.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Utils.GitHub; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/ICredentialsProvider.cs b/src/Tgstation.Server.Host/Components/Repository/ICredentialsProvider.cs index cef08354c67..d120754a5e1 100644 --- a/src/Tgstation.Server.Host/Components/Repository/ICredentialsProvider.cs +++ b/src/Tgstation.Server.Host/Components/Repository/ICredentialsProvider.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.Jobs; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/IGitRemoteAdditionalInformation.cs b/src/Tgstation.Server.Host/Components/Repository/IGitRemoteAdditionalInformation.cs index ffead020f9c..a933a85ad18 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IGitRemoteAdditionalInformation.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IGitRemoteAdditionalInformation.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/IGitRemoteFeaturesFactory.cs b/src/Tgstation.Server.Host/Components/Repository/IGitRemoteFeaturesFactory.cs index 42a55e6285c..dd4ee7de3a9 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IGitRemoteFeaturesFactory.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IGitRemoteFeaturesFactory.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Api.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/ILibGit2Commands.cs b/src/Tgstation.Server.Host/Components/Repository/ILibGit2Commands.cs index 6c0ab0da498..e4fc821ec40 100644 --- a/src/Tgstation.Server.Host/Components/Repository/ILibGit2Commands.cs +++ b/src/Tgstation.Server.Host/Components/Repository/ILibGit2Commands.cs @@ -2,6 +2,8 @@ using LibGit2Sharp; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/ILibGit2RepositoryFactory.cs b/src/Tgstation.Server.Host/Components/Repository/ILibGit2RepositoryFactory.cs index 34b8c566691..b69df2783f7 100644 --- a/src/Tgstation.Server.Host/Components/Repository/ILibGit2RepositoryFactory.cs +++ b/src/Tgstation.Server.Host/Components/Repository/ILibGit2RepositoryFactory.cs @@ -4,6 +4,8 @@ using LibGit2Sharp; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepository.cs b/src/Tgstation.Server.Host/Components/Repository/IRepository.cs index 0482eaaa902..ed858ab4924 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IRepository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IRepository.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Jobs; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs index d602730e151..090e3cad82c 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Jobs; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManagerFactory.cs b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManagerFactory.cs index 0e8c54c70e9..049ad396dee 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManagerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManagerFactory.cs @@ -1,6 +1,8 @@ using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/LibGit2Commands.cs b/src/Tgstation.Server.Host/Components/Repository/LibGit2Commands.cs index ec5c37a880c..b70dc7b1562 100644 --- a/src/Tgstation.Server.Host/Components/Repository/LibGit2Commands.cs +++ b/src/Tgstation.Server.Host/Components/Repository/LibGit2Commands.cs @@ -3,6 +3,8 @@ using LibGit2Sharp; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/LibGit2RepositoryFactory.cs b/src/Tgstation.Server.Host/Components/Repository/LibGit2RepositoryFactory.cs index 83011a61b1a..e47d1a553f8 100644 --- a/src/Tgstation.Server.Host/Components/Repository/LibGit2RepositoryFactory.cs +++ b/src/Tgstation.Server.Host/Components/Repository/LibGit2RepositoryFactory.cs @@ -10,6 +10,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs index a3b81d2bad7..7c8328344af 100644 --- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs @@ -18,6 +18,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs index 2940e0d1349..2bbe2be2d6f 100644 --- a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs +++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs @@ -13,6 +13,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs index 418dc9462d5..8b00701f69c 100644 --- a/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs +++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs @@ -15,6 +15,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/RepostoryManagerFactory.cs b/src/Tgstation.Server.Host/Components/Repository/RepostoryManagerFactory.cs index cba66ff69a4..140b79f03c3 100644 --- a/src/Tgstation.Server.Host/Components/Repository/RepostoryManagerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Repository/RepostoryManagerFactory.cs @@ -9,6 +9,8 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Repository/TestMergeResult.cs b/src/Tgstation.Server.Host/Components/Repository/TestMergeResult.cs index 387a6baad1f..c722590e30f 100644 --- a/src/Tgstation.Server.Host/Components/Repository/TestMergeResult.cs +++ b/src/Tgstation.Server.Host/Components/Repository/TestMergeResult.cs @@ -2,6 +2,8 @@ using LibGit2Sharp; +#nullable disable + namespace Tgstation.Server.Host.Components.Repository { /// diff --git a/src/Tgstation.Server.Host/Components/Session/CombinedTopicResponse.cs b/src/Tgstation.Server.Host/Components/Session/CombinedTopicResponse.cs index 417934f04a8..2b7a09b1749 100644 --- a/src/Tgstation.Server.Host/Components/Session/CombinedTopicResponse.cs +++ b/src/Tgstation.Server.Host/Components/Session/CombinedTopicResponse.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Host.Components.Interop.Topic; +#nullable disable + namespace Tgstation.Server.Host.Components.Session { /// diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs index 2769aafa60b..d42190c78f6 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Host.Components.Interop.Topic; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Components.Session { /// diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs index 26cc5e4a634..34f58c8cc07 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Components.Engine; +#nullable disable + namespace Tgstation.Server.Host.Components.Session { /// diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs index 5b1f1d72007..597208530ee 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs @@ -1,6 +1,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Components.Session { /// diff --git a/src/Tgstation.Server.Host/Components/Session/ITopicClientFactory.cs b/src/Tgstation.Server.Host/Components/Session/ITopicClientFactory.cs index c4be5235a1d..7f60ace9d0c 100644 --- a/src/Tgstation.Server.Host/Components/Session/ITopicClientFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/ITopicClientFactory.cs @@ -2,6 +2,8 @@ using Byond.TopicSender; +#nullable disable + namespace Tgstation.Server.Host.Components.Session { /// diff --git a/src/Tgstation.Server.Host/Components/Session/LaunchResult.cs b/src/Tgstation.Server.Host/Components/Session/LaunchResult.cs index fd5785fd416..de536ce83e6 100644 --- a/src/Tgstation.Server.Host/Components/Session/LaunchResult.cs +++ b/src/Tgstation.Server.Host/Components/Session/LaunchResult.cs @@ -1,6 +1,8 @@ using System; using System.Globalization; +#nullable disable + namespace Tgstation.Server.Host.Components.Session { /// diff --git a/src/Tgstation.Server.Host/Components/Session/ReattachInformation.cs b/src/Tgstation.Server.Host/Components/Session/ReattachInformation.cs index 6c429d2d0a6..3ddeff51d76 100644 --- a/src/Tgstation.Server.Host/Components/Session/ReattachInformation.cs +++ b/src/Tgstation.Server.Host/Components/Session/ReattachInformation.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Components.Session { /// diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index d3feab14a6b..0b191289cbd 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -25,6 +25,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Session { /// diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index a54f9f8874d..79abda99a87 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -26,6 +26,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Session { /// diff --git a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs index e932fa6ec79..7eebd9a2af2 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs @@ -12,6 +12,8 @@ using Z.EntityFramework.Plus; +#nullable disable + namespace Tgstation.Server.Host.Components.Session { /// diff --git a/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs b/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs index 40605e5de8e..e319b53ec58 100644 --- a/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs @@ -3,6 +3,8 @@ using Byond.TopicSender; using Microsoft.Extensions.Logging; +#nullable disable + namespace Tgstation.Server.Host.Components.Session { /// diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs index f42b4cc7e2c..5208567047f 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs @@ -23,6 +23,8 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.StaticFiles { /// diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs index 59546a044ef..63b940d6469 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.Security; +#nullable disable + namespace Tgstation.Server.Host.Components.StaticFiles { /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs index 33140b9e575..ed3c507317d 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs @@ -18,6 +18,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Watchdog { /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index 5beaab473cf..d9f37a6f555 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -17,6 +17,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Watchdog { /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs index a54cde8e838..cd886066008 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.Components.Session; +#nullable disable + namespace Tgstation.Server.Host.Components.Watchdog { /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs index 308cd3db54c..eff60cf7111 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Host.Components.Session; using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Components.Watchdog { /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs index 27874178afa..7b142d6b546 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs @@ -17,6 +17,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Watchdog { /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdogFactory.cs index 1d0d140bc05..491f0ff3625 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdogFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdogFactory.cs @@ -16,6 +16,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Watchdog { /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index 33b5ca07201..e9bca68ee96 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -27,6 +27,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Watchdog { /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs index e9a37ecb2b5..868155d3dcf 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs @@ -15,6 +15,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Watchdog { /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs index cd8f0b45255..98a8d0da466 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs @@ -15,6 +15,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Watchdog { /// diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs index 89ed6b145d7..cd78148c373 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs @@ -15,6 +15,8 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Components.Watchdog { /// diff --git a/src/Tgstation.Server.Host/Configuration/ControlPanelConfiguration.cs b/src/Tgstation.Server.Host/Configuration/ControlPanelConfiguration.cs index 19dfa9cace0..437a420495e 100644 --- a/src/Tgstation.Server.Host/Configuration/ControlPanelConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/ControlPanelConfiguration.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable disable + namespace Tgstation.Server.Host.Configuration { /// diff --git a/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs b/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs index d5adce7577f..51e78a2494c 100644 --- a/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs @@ -1,6 +1,8 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; +#nullable disable + namespace Tgstation.Server.Host.Configuration { /// diff --git a/src/Tgstation.Server.Host/Configuration/ElasticsearchConfiguration.cs b/src/Tgstation.Server.Host/Configuration/ElasticsearchConfiguration.cs index 8c45f2e9f5f..424d746a67a 100644 --- a/src/Tgstation.Server.Host/Configuration/ElasticsearchConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/ElasticsearchConfiguration.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.Configuration { /// diff --git a/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs b/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs index aa798cfed36..6d73d95ad9c 100644 --- a/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Configuration { /// diff --git a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs index f33ef79b11c..a21f796dc7f 100644 --- a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs @@ -11,6 +11,8 @@ using YamlDotNet.Serialization; +#nullable disable + namespace Tgstation.Server.Host.Configuration { /// diff --git a/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs b/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs index 6bf30bafdc7..315cdad35c6 100644 --- a/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.Configuration +#nullable disable + +namespace Tgstation.Server.Host.Configuration { /// /// Unstable configuration options used internally by TGS. diff --git a/src/Tgstation.Server.Host/Configuration/OAuthConfiguration.cs b/src/Tgstation.Server.Host/Configuration/OAuthConfiguration.cs index 1818a15d8b2..ae1005b00e6 100644 --- a/src/Tgstation.Server.Host/Configuration/OAuthConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/OAuthConfiguration.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.Configuration { /// diff --git a/src/Tgstation.Server.Host/Configuration/OAuthConfigurationBase.cs b/src/Tgstation.Server.Host/Configuration/OAuthConfigurationBase.cs index d2d76680728..ab77c0fcbc2 100644 --- a/src/Tgstation.Server.Host/Configuration/OAuthConfigurationBase.cs +++ b/src/Tgstation.Server.Host/Configuration/OAuthConfigurationBase.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.Configuration { /// diff --git a/src/Tgstation.Server.Host/Configuration/SecurityConfiguration.cs b/src/Tgstation.Server.Host/Configuration/SecurityConfiguration.cs index a6073538cd9..f6df85278c9 100644 --- a/src/Tgstation.Server.Host/Configuration/SecurityConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/SecurityConfiguration.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Api.Models; +#nullable disable + namespace Tgstation.Server.Host.Configuration { /// diff --git a/src/Tgstation.Server.Host/Configuration/SwarmConfiguration.cs b/src/Tgstation.Server.Host/Configuration/SwarmConfiguration.cs index 38c709ec399..417203bd1b8 100644 --- a/src/Tgstation.Server.Host/Configuration/SwarmConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/SwarmConfiguration.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Api.Models.Internal; using YamlDotNet.Serialization; +#nullable disable + namespace Tgstation.Server.Host.Configuration { /// diff --git a/src/Tgstation.Server.Host/Configuration/UpdatesConfiguration.cs b/src/Tgstation.Server.Host/Configuration/UpdatesConfiguration.cs index 1e340c84caa..a8a4b6c932b 100644 --- a/src/Tgstation.Server.Host/Configuration/UpdatesConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/UpdatesConfiguration.cs @@ -1,5 +1,7 @@ using Tgstation.Server.Common; +#nullable disable + namespace Tgstation.Server.Host.Configuration { /// diff --git a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs index c1da69a69d6..f90a842a5c1 100644 --- a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs +++ b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs @@ -29,6 +29,8 @@ using Tgstation.Server.Host.Utils; using Tgstation.Server.Host.Utils.GitHub; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/ApiController.cs b/src/Tgstation.Server.Host/Controllers/ApiController.cs index ffa4e849600..561bde364b5 100644 --- a/src/Tgstation.Server.Host/Controllers/ApiController.cs +++ b/src/Tgstation.Server.Host/Controllers/ApiController.cs @@ -28,6 +28,8 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/ApiControllerBase.cs b/src/Tgstation.Server.Host/Controllers/ApiControllerBase.cs index 9a8b1198082..8e313397f1c 100644 --- a/src/Tgstation.Server.Host/Controllers/ApiControllerBase.cs +++ b/src/Tgstation.Server.Host/Controllers/ApiControllerBase.cs @@ -8,6 +8,8 @@ using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/ApiRootController.cs b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs index fbfc1d44659..5480c689d21 100644 --- a/src/Tgstation.Server.Host/Controllers/ApiRootController.cs +++ b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs @@ -27,6 +27,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/BridgeController.cs b/src/Tgstation.Server.Host/Controllers/BridgeController.cs index a1acb954a92..96c44f5085c 100644 --- a/src/Tgstation.Server.Host/Controllers/BridgeController.cs +++ b/src/Tgstation.Server.Host/Controllers/BridgeController.cs @@ -18,6 +18,8 @@ using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/ChatController.cs b/src/Tgstation.Server.Host/Controllers/ChatController.cs index 967971eb248..551d03d9435 100644 --- a/src/Tgstation.Server.Host/Controllers/ChatController.cs +++ b/src/Tgstation.Server.Host/Controllers/ChatController.cs @@ -27,6 +27,8 @@ using Tgstation.Server.Host.Utils; using Z.EntityFramework.Plus; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs b/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs index eef1af8b180..c830a45d17b 100644 --- a/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs +++ b/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs @@ -13,6 +13,8 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs b/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs index 37b7e89ed1d..2b95796ef7e 100644 --- a/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs +++ b/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs @@ -19,6 +19,8 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs b/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs index 08d8f74dad1..1d2d1274b82 100644 --- a/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs +++ b/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs @@ -16,6 +16,8 @@ using Tgstation.Server.Api; using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index 5a3ff51f0e5..2ccd942edb6 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -25,6 +25,8 @@ #pragma warning disable API1001 // Action method returns a success result without a corresponding ProducesResponseType. Somehow this happens ONLY IN THIS CONTROLLER??? +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs index 714713763f9..9401f646d9f 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs @@ -21,6 +21,8 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/EngineController.cs b/src/Tgstation.Server.Host/Controllers/EngineController.cs index 75c7ef289b8..a65ac974557 100644 --- a/src/Tgstation.Server.Host/Controllers/EngineController.cs +++ b/src/Tgstation.Server.Host/Controllers/EngineController.cs @@ -23,6 +23,8 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index d63396daf9c..471a0fd0067 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -29,6 +29,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs index 13defd80481..d5d4a0fb79f 100644 --- a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs @@ -22,6 +22,8 @@ using Z.EntityFramework.Plus; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs b/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs index cdf3f0e139c..6ee1fe49632 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/JobController.cs b/src/Tgstation.Server.Host/Controllers/JobController.cs index 521a560a0b8..6019223426e 100644 --- a/src/Tgstation.Server.Host/Controllers/JobController.cs +++ b/src/Tgstation.Server.Host/Controllers/JobController.cs @@ -19,6 +19,8 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs index 6bc447a0449..dbf80a4171e 100644 --- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs +++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs @@ -24,6 +24,8 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResult.cs b/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResult.cs index 998f5779c5c..10b0e08909c 100644 --- a/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResult.cs +++ b/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResult.cs @@ -10,6 +10,8 @@ using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Controllers.Results { /// diff --git a/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResultExecutor.cs b/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResultExecutor.cs index 3178db355b4..2a7bc72279b 100644 --- a/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResultExecutor.cs +++ b/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResultExecutor.cs @@ -7,6 +7,8 @@ using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.Logging; +#nullable disable + namespace Tgstation.Server.Host.Controllers.Results { /// diff --git a/src/Tgstation.Server.Host/Controllers/Results/PaginatableResult.cs b/src/Tgstation.Server.Host/Controllers/Results/PaginatableResult.cs index b936d0f3e6e..7be3c27aa19 100644 --- a/src/Tgstation.Server.Host/Controllers/Results/PaginatableResult.cs +++ b/src/Tgstation.Server.Host/Controllers/Results/PaginatableResult.cs @@ -3,6 +3,8 @@ using Microsoft.AspNetCore.Mvc; +#nullable disable + namespace Tgstation.Server.Host.Controllers.Results { /// diff --git a/src/Tgstation.Server.Host/Controllers/RootController.cs b/src/Tgstation.Server.Host/Controllers/RootController.cs index 850785d6125..c063984cc19 100644 --- a/src/Tgstation.Server.Host/Controllers/RootController.cs +++ b/src/Tgstation.Server.Host/Controllers/RootController.cs @@ -9,6 +9,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/SwarmController.cs b/src/Tgstation.Server.Host/Controllers/SwarmController.cs index 2512eda8dd6..c56cfaa5c8a 100644 --- a/src/Tgstation.Server.Host/Controllers/SwarmController.cs +++ b/src/Tgstation.Server.Host/Controllers/SwarmController.cs @@ -19,6 +19,8 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/TransferController.cs b/src/Tgstation.Server.Host/Controllers/TransferController.cs index 8a0a2ebcd3f..07feea08a0b 100644 --- a/src/Tgstation.Server.Host/Controllers/TransferController.cs +++ b/src/Tgstation.Server.Host/Controllers/TransferController.cs @@ -16,6 +16,8 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/UserController.cs b/src/Tgstation.Server.Host/Controllers/UserController.cs index 08c61e05fe0..8eed28d3f54 100644 --- a/src/Tgstation.Server.Host/Controllers/UserController.cs +++ b/src/Tgstation.Server.Host/Controllers/UserController.cs @@ -22,6 +22,8 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Controllers/UserGroupController.cs b/src/Tgstation.Server.Host/Controllers/UserGroupController.cs index 3f2c5ea3a24..d50bc8e9c51 100644 --- a/src/Tgstation.Server.Host/Controllers/UserGroupController.cs +++ b/src/Tgstation.Server.Host/Controllers/UserGroupController.cs @@ -23,6 +23,8 @@ using Z.EntityFramework.Plus; +#nullable disable + namespace Tgstation.Server.Host.Controllers { /// diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 3ce52f39beb..404655f3796 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -63,6 +63,8 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Core/CommandPipeManager.cs b/src/Tgstation.Server.Host/Core/CommandPipeManager.cs index cd06a7a0738..798b7db57ca 100644 --- a/src/Tgstation.Server.Host/Core/CommandPipeManager.cs +++ b/src/Tgstation.Server.Host/Core/CommandPipeManager.cs @@ -13,6 +13,8 @@ using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Core/IRestartHandler.cs b/src/Tgstation.Server.Host/Core/IRestartHandler.cs index e1c8a771ef5..4db9ad18c3d 100644 --- a/src/Tgstation.Server.Host/Core/IRestartHandler.cs +++ b/src/Tgstation.Server.Host/Core/IRestartHandler.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Core/IRestartRegistration.cs b/src/Tgstation.Server.Host/Core/IRestartRegistration.cs index 586d73f0047..ee2ddc7ddfa 100644 --- a/src/Tgstation.Server.Host/Core/IRestartRegistration.cs +++ b/src/Tgstation.Server.Host/Core/IRestartRegistration.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Core/IServerControl.cs b/src/Tgstation.Server.Host/Core/IServerControl.cs index d864080db69..8eca773ecb9 100644 --- a/src/Tgstation.Server.Host/Core/IServerControl.cs +++ b/src/Tgstation.Server.Host/Core/IServerControl.cs @@ -1,6 +1,8 @@ using System; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Core/IServerUpdateExecutor.cs b/src/Tgstation.Server.Host/Core/IServerUpdateExecutor.cs index c2bf6f2090c..9a1ea2d0119 100644 --- a/src/Tgstation.Server.Host/Core/IServerUpdateExecutor.cs +++ b/src/Tgstation.Server.Host/Core/IServerUpdateExecutor.cs @@ -1,6 +1,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Core/IServerUpdateInitiator.cs b/src/Tgstation.Server.Host/Core/IServerUpdateInitiator.cs index 8b290bdcd2c..f9af6f34de7 100644 --- a/src/Tgstation.Server.Host/Core/IServerUpdateInitiator.cs +++ b/src/Tgstation.Server.Host/Core/IServerUpdateInitiator.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Core/IServerUpdater.cs b/src/Tgstation.Server.Host/Core/IServerUpdater.cs index 6485ed47134..de0e38b67d8 100644 --- a/src/Tgstation.Server.Host/Core/IServerUpdater.cs +++ b/src/Tgstation.Server.Host/Core/IServerUpdater.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Swarm; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Core/RestartRegistration.cs b/src/Tgstation.Server.Host/Core/RestartRegistration.cs index 025c274e075..d685fe590b4 100644 --- a/src/Tgstation.Server.Host/Core/RestartRegistration.cs +++ b/src/Tgstation.Server.Host/Core/RestartRegistration.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Core/ServerPortProivder.cs b/src/Tgstation.Server.Host/Core/ServerPortProivder.cs index e4c4927c534..0b97105c43f 100644 --- a/src/Tgstation.Server.Host/Core/ServerPortProivder.cs +++ b/src/Tgstation.Server.Host/Core/ServerPortProivder.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Core/ServerUpdateInitiator.cs b/src/Tgstation.Server.Host/Core/ServerUpdateInitiator.cs index f7fad731229..0819b4ddd5a 100644 --- a/src/Tgstation.Server.Host/Core/ServerUpdateInitiator.cs +++ b/src/Tgstation.Server.Host/Core/ServerUpdateInitiator.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Swarm; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Core/ServerUpdateOperation.cs b/src/Tgstation.Server.Host/Core/ServerUpdateOperation.cs index f14d85ec752..1e673f82395 100644 --- a/src/Tgstation.Server.Host/Core/ServerUpdateOperation.cs +++ b/src/Tgstation.Server.Host/Core/ServerUpdateOperation.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Swarm; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Core/ServerUpdater.cs b/src/Tgstation.Server.Host/Core/ServerUpdater.cs index aacf44fd193..be3b9f033c6 100644 --- a/src/Tgstation.Server.Host/Core/ServerUpdater.cs +++ b/src/Tgstation.Server.Host/Core/ServerUpdater.cs @@ -11,6 +11,8 @@ using Tgstation.Server.Host.Swarm; using Tgstation.Server.Host.Utils.GitHub; +#nullable disable + namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Database/DatabaseCollection.cs b/src/Tgstation.Server.Host/Database/DatabaseCollection.cs index b2dafa719dc..831772335bb 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseCollection.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseCollection.cs @@ -7,6 +7,8 @@ using Microsoft.EntityFrameworkCore; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs b/src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs index b118f346dbb..7cc0e2e5ed0 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs @@ -10,6 +10,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/DatabaseContext.cs b/src/Tgstation.Server.Host/Database/DatabaseContext.cs index cca6313b532..6b1ce65d232 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseContext.cs @@ -15,6 +15,8 @@ using Tgstation.Server.Host.Database.Migrations; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/DatabaseContextFactory.cs b/src/Tgstation.Server.Host/Database/DatabaseContextFactory.cs index b04e32858b3..854bc6ea65c 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseContextFactory.cs @@ -3,6 +3,8 @@ using Microsoft.Extensions.DependencyInjection; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs b/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs index 19efc59b471..51bf71bc6d3 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs @@ -16,6 +16,8 @@ using Z.EntityFramework.Plus; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs b/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs index 54d79bddc35..b8527648bbd 100644 --- a/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs +++ b/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Database.Design { /// diff --git a/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs index f67028efffc..86efd5568f8 100644 --- a/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Database.Design { /// diff --git a/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs index 965eade13e1..11151e5e582 100644 --- a/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Common; using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Database.Design { /// diff --git a/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs index 9b5623725e1..ac0704df2a6 100644 --- a/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Database.Design { /// diff --git a/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs index 924d8934f99..f4c36cb31fb 100644 --- a/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Database.Design { /// diff --git a/src/Tgstation.Server.Host/Database/IDatabaseCollection.cs b/src/Tgstation.Server.Host/Database/IDatabaseCollection.cs index a9e1fe0e03c..08df6330f9a 100644 --- a/src/Tgstation.Server.Host/Database/IDatabaseCollection.cs +++ b/src/Tgstation.Server.Host/Database/IDatabaseCollection.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.Linq; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/IDatabaseConnectionFactory.cs b/src/Tgstation.Server.Host/Database/IDatabaseConnectionFactory.cs index abea5f17026..7ce5ba0f5f0 100644 --- a/src/Tgstation.Server.Host/Database/IDatabaseConnectionFactory.cs +++ b/src/Tgstation.Server.Host/Database/IDatabaseConnectionFactory.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/IDatabaseContext.cs b/src/Tgstation.Server.Host/Database/IDatabaseContext.cs index 00b90298c67..dc276cf371c 100644 --- a/src/Tgstation.Server.Host/Database/IDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/IDatabaseContext.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/IDatabaseContextFactory.cs b/src/Tgstation.Server.Host/Database/IDatabaseContextFactory.cs index 4004c873c08..a51906ff409 100644 --- a/src/Tgstation.Server.Host/Database/IDatabaseContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/IDatabaseContextFactory.cs @@ -1,6 +1,8 @@ using System; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/IDatabaseSeeder.cs b/src/Tgstation.Server.Host/Database/IDatabaseSeeder.cs index e888b0093a8..76c0761fb91 100644 --- a/src/Tgstation.Server.Host/Database/IDatabaseSeeder.cs +++ b/src/Tgstation.Server.Host/Database/IDatabaseSeeder.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs b/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs index 4bdcf9a066d..68112d5fb2c 100644 --- a/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/PostgresSqlDatabaseContext.cs b/src/Tgstation.Server.Host/Database/PostgresSqlDatabaseContext.cs index d9157ab41a5..952f515347d 100644 --- a/src/Tgstation.Server.Host/Database/PostgresSqlDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/PostgresSqlDatabaseContext.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs b/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs index 3997e0a46b3..10e1f6d16ff 100644 --- a/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs b/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs index 98a58190d91..1a35d2e7697 100644 --- a/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Extensions/ApplicationBuilderExtensions.cs b/src/Tgstation.Server.Host/Extensions/ApplicationBuilderExtensions.cs index 637484f5bd1..1e69a743f0b 100644 --- a/src/Tgstation.Server.Host/Extensions/ApplicationBuilderExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ApplicationBuilderExtensions.cs @@ -17,6 +17,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs b/src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs index edfb7bb4264..e4bb8948e3e 100644 --- a/src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs b/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs index 9ab3b1cc87e..73f87308c7a 100644 --- a/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/Converters/BoolConverter.cs b/src/Tgstation.Server.Host/Extensions/Converters/BoolConverter.cs index ece30522829..502980a212b 100644 --- a/src/Tgstation.Server.Host/Extensions/Converters/BoolConverter.cs +++ b/src/Tgstation.Server.Host/Extensions/Converters/BoolConverter.cs @@ -2,6 +2,8 @@ using Newtonsoft.Json; +#nullable disable + namespace Tgstation.Server.Host.Extensions.Converters { /// diff --git a/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs b/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs index 0373dc5e20e..e1bf992cab2 100644 --- a/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs +++ b/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs @@ -8,6 +8,8 @@ using YamlDotNet.Core.Events; using YamlDotNet.Serialization; +#nullable disable + namespace Tgstation.Server.Host.Extensions.Converters { /// diff --git a/src/Tgstation.Server.Host/Extensions/DatabaseCollectionExtensions.cs b/src/Tgstation.Server.Host/Extensions/DatabaseCollectionExtensions.cs index ea50a7af172..40f005609c9 100644 --- a/src/Tgstation.Server.Host/Extensions/DatabaseCollectionExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/DatabaseCollectionExtensions.cs @@ -9,6 +9,8 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/DateTimeOffsetExtensions.cs b/src/Tgstation.Server.Host/Extensions/DateTimeOffsetExtensions.cs index 44b0669314f..1d3a864cf96 100644 --- a/src/Tgstation.Server.Host/Extensions/DateTimeOffsetExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/DateTimeOffsetExtensions.cs @@ -1,6 +1,8 @@ using System; using System.Globalization; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/FileTransferStreamHandlerExtensions.cs b/src/Tgstation.Server.Host/Extensions/FileTransferStreamHandlerExtensions.cs index a7e84abac19..632bd0bd722 100644 --- a/src/Tgstation.Server.Host/Extensions/FileTransferStreamHandlerExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/FileTransferStreamHandlerExtensions.cs @@ -14,6 +14,8 @@ using Tgstation.Server.Host.Controllers.Results; using Tgstation.Server.Host.Transfer; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/GeneralConfigurationExtensions.cs b/src/Tgstation.Server.Host/Extensions/GeneralConfigurationExtensions.cs index 0a2a5fc8d84..5214ed0085f 100644 --- a/src/Tgstation.Server.Host/Extensions/GeneralConfigurationExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/GeneralConfigurationExtensions.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/HostBuilderExtensions.cs b/src/Tgstation.Server.Host/Extensions/HostBuilderExtensions.cs index 6bfc4cb528f..160293e7442 100644 --- a/src/Tgstation.Server.Host/Extensions/HostBuilderExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/HostBuilderExtensions.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Host.Setup; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs b/src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs index f503f2c7179..8ecf17c6006 100644 --- a/src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Api.Models; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/ResultExtensions.cs b/src/Tgstation.Server.Host/Extensions/ResultExtensions.cs index 5d4370734f6..4f7d3bc4a4a 100644 --- a/src/Tgstation.Server.Host/Extensions/ResultExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ResultExtensions.cs @@ -7,6 +7,8 @@ using Remora.Rest.Results; using Remora.Results; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs b/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs index c90433f1ff0..f32d2a675d1 100644 --- a/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs @@ -18,6 +18,8 @@ using Tgstation.Server.Host.Utils.GitHub; using Tgstation.Server.Host.Utils.SignalR; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs index 6c1a695025e..1c74a95a500 100644 --- a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs b/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs index 55b6701dbbf..b2e5eaaf9e5 100644 --- a/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs @@ -1,5 +1,7 @@ using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/Extensions/WebHostBuilderExtensions.cs b/src/Tgstation.Server.Host/Extensions/WebHostBuilderExtensions.cs index e6815cd7a0f..c2f430e1723 100644 --- a/src/Tgstation.Server.Host/Extensions/WebHostBuilderExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/WebHostBuilderExtensions.cs @@ -13,6 +13,8 @@ using Tgstation.Server.Host.Setup; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Extensions { /// diff --git a/src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs b/src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs index c3248698601..e4a8fcd139b 100644 --- a/src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs +++ b/src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/Console.cs b/src/Tgstation.Server.Host/IO/Console.cs index fdf06eea52c..ae6efa4ed7f 100644 --- a/src/Tgstation.Server.Host/IO/Console.cs +++ b/src/Tgstation.Server.Host/IO/Console.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs index 4841980dd35..321271faf94 100644 --- a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs +++ b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/FileDownloader.cs b/src/Tgstation.Server.Host/IO/FileDownloader.cs index 1aa554e647c..1b133e9647c 100644 --- a/src/Tgstation.Server.Host/IO/FileDownloader.cs +++ b/src/Tgstation.Server.Host/IO/FileDownloader.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Api; using Tgstation.Server.Common.Http; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/IConsole.cs b/src/Tgstation.Server.Host/IO/IConsole.cs index 605f3e421d9..cc71295c554 100644 --- a/src/Tgstation.Server.Host/IO/IConsole.cs +++ b/src/Tgstation.Server.Host/IO/IConsole.cs @@ -1,6 +1,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/IFileDownloader.cs b/src/Tgstation.Server.Host/IO/IFileDownloader.cs index 5a2c9891709..6cc9baad869 100644 --- a/src/Tgstation.Server.Host/IO/IFileDownloader.cs +++ b/src/Tgstation.Server.Host/IO/IFileDownloader.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/IFileStreamProvider.cs b/src/Tgstation.Server.Host/IO/IFileStreamProvider.cs index e27f779314f..47a2caca10a 100644 --- a/src/Tgstation.Server.Host/IO/IFileStreamProvider.cs +++ b/src/Tgstation.Server.Host/IO/IFileStreamProvider.cs @@ -3,6 +3,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/IFilesystemLinkFactory.cs b/src/Tgstation.Server.Host/IO/IFilesystemLinkFactory.cs index 3cf0622801a..36ea58a9dfa 100644 --- a/src/Tgstation.Server.Host/IO/IFilesystemLinkFactory.cs +++ b/src/Tgstation.Server.Host/IO/IFilesystemLinkFactory.cs @@ -1,6 +1,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/IIOManager.cs b/src/Tgstation.Server.Host/IO/IIOManager.cs index 0b249b23a24..b66bd6f0fab 100644 --- a/src/Tgstation.Server.Host/IO/IIOManager.cs +++ b/src/Tgstation.Server.Host/IO/IIOManager.cs @@ -4,6 +4,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/ISeekableFileStreamProvider.cs b/src/Tgstation.Server.Host/IO/ISeekableFileStreamProvider.cs index 7a6b76eb0d4..f34e28745d1 100644 --- a/src/Tgstation.Server.Host/IO/ISeekableFileStreamProvider.cs +++ b/src/Tgstation.Server.Host/IO/ISeekableFileStreamProvider.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/ISynchronousIOManager.cs b/src/Tgstation.Server.Host/IO/ISynchronousIOManager.cs index 36f90140aa1..df87b894c6f 100644 --- a/src/Tgstation.Server.Host/IO/ISynchronousIOManager.cs +++ b/src/Tgstation.Server.Host/IO/ISynchronousIOManager.cs @@ -2,6 +2,8 @@ using System.IO; using System.Threading; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/PosixFilesystemLinkFactory.cs b/src/Tgstation.Server.Host/IO/PosixFilesystemLinkFactory.cs index b80af9e122a..b5355d9aad7 100644 --- a/src/Tgstation.Server.Host/IO/PosixFilesystemLinkFactory.cs +++ b/src/Tgstation.Server.Host/IO/PosixFilesystemLinkFactory.cs @@ -5,6 +5,8 @@ using Mono.Unix; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/PosixPostWriteHandler.cs b/src/Tgstation.Server.Host/IO/PosixPostWriteHandler.cs index a0f4f5a4c8a..ec441813b17 100644 --- a/src/Tgstation.Server.Host/IO/PosixPostWriteHandler.cs +++ b/src/Tgstation.Server.Host/IO/PosixPostWriteHandler.cs @@ -4,6 +4,8 @@ using Mono.Unix; using Mono.Unix.Native; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs b/src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs index c0c100cfcf7..ef4ddb0d145 100644 --- a/src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs +++ b/src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Common.Http; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/ResolvingIOManager.cs b/src/Tgstation.Server.Host/IO/ResolvingIOManager.cs index 3b86b92c36a..665a5b6bc4a 100644 --- a/src/Tgstation.Server.Host/IO/ResolvingIOManager.cs +++ b/src/Tgstation.Server.Host/IO/ResolvingIOManager.cs @@ -1,6 +1,8 @@ using System; using System.IO; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/SynchronousIOManager.cs b/src/Tgstation.Server.Host/IO/SynchronousIOManager.cs index a629ddcff44..590cbfbb6fe 100644 --- a/src/Tgstation.Server.Host/IO/SynchronousIOManager.cs +++ b/src/Tgstation.Server.Host/IO/SynchronousIOManager.cs @@ -6,6 +6,8 @@ using System.Security.Cryptography; using System.Threading; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs b/src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs index 1513f4e1666..5a410ab3d79 100644 --- a/src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs +++ b/src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs @@ -6,6 +6,8 @@ using BetterWin32Errors; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IO/WindowsPostWriteHandler.cs b/src/Tgstation.Server.Host/IO/WindowsPostWriteHandler.cs index 2a94e42a2fe..a2b6b0d4ae0 100644 --- a/src/Tgstation.Server.Host/IO/WindowsPostWriteHandler.cs +++ b/src/Tgstation.Server.Host/IO/WindowsPostWriteHandler.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.IO { /// diff --git a/src/Tgstation.Server.Host/IServer.cs b/src/Tgstation.Server.Host/IServer.cs index e13364831f6..105b14f7736 100644 --- a/src/Tgstation.Server.Host/IServer.cs +++ b/src/Tgstation.Server.Host/IServer.cs @@ -1,6 +1,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host { /// diff --git a/src/Tgstation.Server.Host/IServerFactory.cs b/src/Tgstation.Server.Host/IServerFactory.cs index 46f95105231..937fee71846 100644 --- a/src/Tgstation.Server.Host/IServerFactory.cs +++ b/src/Tgstation.Server.Host/IServerFactory.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host { /// diff --git a/src/Tgstation.Server.Host/Jobs/IJobManager.cs b/src/Tgstation.Server.Host/Jobs/IJobManager.cs index 80ef2008592..e8d0a83bafb 100644 --- a/src/Tgstation.Server.Host/Jobs/IJobManager.cs +++ b/src/Tgstation.Server.Host/Jobs/IJobManager.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Jobs { /// diff --git a/src/Tgstation.Server.Host/Jobs/IJobService.cs b/src/Tgstation.Server.Host/Jobs/IJobService.cs index e92ead5e6a6..847adff98ca 100644 --- a/src/Tgstation.Server.Host/Jobs/IJobService.cs +++ b/src/Tgstation.Server.Host/Jobs/IJobService.cs @@ -1,5 +1,7 @@ using Tgstation.Server.Host.Components; +#nullable disable + namespace Tgstation.Server.Host.Jobs { /// diff --git a/src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs b/src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs index 79e71b5048c..1a272153069 100644 --- a/src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs +++ b/src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Jobs { /// diff --git a/src/Tgstation.Server.Host/Jobs/JobException.cs b/src/Tgstation.Server.Host/Jobs/JobException.cs index 0eb62f2e29e..d29697252fe 100644 --- a/src/Tgstation.Server.Host/Jobs/JobException.cs +++ b/src/Tgstation.Server.Host/Jobs/JobException.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Api.Models; +#nullable disable + namespace Tgstation.Server.Host.Jobs { /// diff --git a/src/Tgstation.Server.Host/Jobs/JobHandler.cs b/src/Tgstation.Server.Host/Jobs/JobHandler.cs index 9d9c692c070..3a290d48ce7 100644 --- a/src/Tgstation.Server.Host/Jobs/JobHandler.cs +++ b/src/Tgstation.Server.Host/Jobs/JobHandler.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Jobs { /// diff --git a/src/Tgstation.Server.Host/Jobs/JobProgressReporter.cs b/src/Tgstation.Server.Host/Jobs/JobProgressReporter.cs index 4d23385e632..37b7ae03e20 100644 --- a/src/Tgstation.Server.Host/Jobs/JobProgressReporter.cs +++ b/src/Tgstation.Server.Host/Jobs/JobProgressReporter.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Jobs { /// diff --git a/src/Tgstation.Server.Host/Jobs/JobService.cs b/src/Tgstation.Server.Host/Jobs/JobService.cs index 87387c60a93..e383bf17460 100644 --- a/src/Tgstation.Server.Host/Jobs/JobService.cs +++ b/src/Tgstation.Server.Host/Jobs/JobService.cs @@ -21,6 +21,8 @@ using Tgstation.Server.Host.Utils; using Tgstation.Server.Host.Utils.SignalR; +#nullable disable + namespace Tgstation.Server.Host.Jobs { /// diff --git a/src/Tgstation.Server.Host/Jobs/JobsHub.cs b/src/Tgstation.Server.Host/Jobs/JobsHub.cs index b74e19d22b0..373fcc5af70 100644 --- a/src/Tgstation.Server.Host/Jobs/JobsHub.cs +++ b/src/Tgstation.Server.Host/Jobs/JobsHub.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils.SignalR; +#nullable disable + namespace Tgstation.Server.Host.Jobs { /// diff --git a/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs b/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs index 2e2a5da93d9..4fe5c710120 100644 --- a/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs +++ b/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs @@ -15,6 +15,8 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils.SignalR; +#nullable disable + namespace Tgstation.Server.Host.Jobs { /// diff --git a/src/Tgstation.Server.Host/Models/ChatBot.cs b/src/Tgstation.Server.Host/Models/ChatBot.cs index f98f4a43c3a..8b5fe59f7db 100644 --- a/src/Tgstation.Server.Host/Models/ChatBot.cs +++ b/src/Tgstation.Server.Host/Models/ChatBot.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/ChatChannel.cs b/src/Tgstation.Server.Host/Models/ChatChannel.cs index a4cbea0952a..85823089cfa 100644 --- a/src/Tgstation.Server.Host/Models/ChatChannel.cs +++ b/src/Tgstation.Server.Host/Models/ChatChannel.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/CompileJob.cs b/src/Tgstation.Server.Host/Models/CompileJob.cs index 59bc7c4d01a..5883302c591 100644 --- a/src/Tgstation.Server.Host/Models/CompileJob.cs +++ b/src/Tgstation.Server.Host/Models/CompileJob.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/DreamDaemonSettings.cs b/src/Tgstation.Server.Host/Models/DreamDaemonSettings.cs index 5a263910154..c58642fd956 100644 --- a/src/Tgstation.Server.Host/Models/DreamDaemonSettings.cs +++ b/src/Tgstation.Server.Host/Models/DreamDaemonSettings.cs @@ -1,5 +1,7 @@ using System.ComponentModel.DataAnnotations; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/DreamMakerSettings.cs b/src/Tgstation.Server.Host/Models/DreamMakerSettings.cs index 3a55c433d0a..88bfe61344b 100644 --- a/src/Tgstation.Server.Host/Models/DreamMakerSettings.cs +++ b/src/Tgstation.Server.Host/Models/DreamMakerSettings.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/Instance.cs b/src/Tgstation.Server.Host/Models/Instance.cs index 82cfd5c7072..d098b60e700 100644 --- a/src/Tgstation.Server.Host/Models/Instance.cs +++ b/src/Tgstation.Server.Host/Models/Instance.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs b/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs index 623e920734b..01bc99ae428 100644 --- a/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs +++ b/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/Job.cs b/src/Tgstation.Server.Host/Models/Job.cs index 674330ee159..c9af1ffa508 100644 --- a/src/Tgstation.Server.Host/Models/Job.cs +++ b/src/Tgstation.Server.Host/Models/Job.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Api.Rights; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/OAuthConnection.cs b/src/Tgstation.Server.Host/Models/OAuthConnection.cs index e72476c1349..df9a15732eb 100644 --- a/src/Tgstation.Server.Host/Models/OAuthConnection.cs +++ b/src/Tgstation.Server.Host/Models/OAuthConnection.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.Models +#nullable disable + +namespace Tgstation.Server.Host.Models { /// public sealed class OAuthConnection : Api.Models.OAuthConnection, IApiTransformable diff --git a/src/Tgstation.Server.Host/Models/PermissionSet.cs b/src/Tgstation.Server.Host/Models/PermissionSet.cs index 021a8239f27..704412c1742 100644 --- a/src/Tgstation.Server.Host/Models/PermissionSet.cs +++ b/src/Tgstation.Server.Host/Models/PermissionSet.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/ReattachInformation.cs b/src/Tgstation.Server.Host/Models/ReattachInformation.cs index d4d1520d08c..80137b50048 100644 --- a/src/Tgstation.Server.Host/Models/ReattachInformation.cs +++ b/src/Tgstation.Server.Host/Models/ReattachInformation.cs @@ -1,5 +1,7 @@ using System.ComponentModel.DataAnnotations; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs b/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs index b233f0c0179..0f8106aa7b0 100644 --- a/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs +++ b/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Session; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/RepositorySettings.cs b/src/Tgstation.Server.Host/Models/RepositorySettings.cs index b62f235d5eb..c5e1d904c25 100644 --- a/src/Tgstation.Server.Host/Models/RepositorySettings.cs +++ b/src/Tgstation.Server.Host/Models/RepositorySettings.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/RevInfoTestMerge.cs b/src/Tgstation.Server.Host/Models/RevInfoTestMerge.cs index 4328910d0c5..64b088343aa 100644 --- a/src/Tgstation.Server.Host/Models/RevInfoTestMerge.cs +++ b/src/Tgstation.Server.Host/Models/RevInfoTestMerge.cs @@ -1,5 +1,7 @@ using System.ComponentModel.DataAnnotations; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/RevisionInformation.cs b/src/Tgstation.Server.Host/Models/RevisionInformation.cs index 290e118ae98..8813e4c5bc9 100644 --- a/src/Tgstation.Server.Host/Models/RevisionInformation.cs +++ b/src/Tgstation.Server.Host/Models/RevisionInformation.cs @@ -2,6 +2,8 @@ using System.ComponentModel.DataAnnotations; using System.Linq; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/TestMerge.cs b/src/Tgstation.Server.Host/Models/TestMerge.cs index 43d7f35b281..3733ca62fcf 100644 --- a/src/Tgstation.Server.Host/Models/TestMerge.cs +++ b/src/Tgstation.Server.Host/Models/TestMerge.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/User.cs b/src/Tgstation.Server.Host/Models/User.cs index 0d275c7d18c..4c4e2c03b03 100644 --- a/src/Tgstation.Server.Host/Models/User.cs +++ b/src/Tgstation.Server.Host/Models/User.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Models/UserGroup.cs b/src/Tgstation.Server.Host/Models/UserGroup.cs index 63f351c3299..65c18474fac 100644 --- a/src/Tgstation.Server.Host/Models/UserGroup.cs +++ b/src/Tgstation.Server.Host/Models/UserGroup.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Models { /// diff --git a/src/Tgstation.Server.Host/Program.cs b/src/Tgstation.Server.Host/Program.cs index e372c0563d6..fb5cf8a1c0b 100644 --- a/src/Tgstation.Server.Host/Program.cs +++ b/src/Tgstation.Server.Host/Program.cs @@ -11,6 +11,8 @@ using Tgstation.Server.Host.Properties; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host { /// diff --git a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs index d6461713bb8..042b679202f 100644 --- a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs +++ b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs @@ -1,6 +1,8 @@ using System; using System.Reflection; +#nullable disable + namespace Tgstation.Server.Host.Properties { /// diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContext.cs b/src/Tgstation.Server.Host/Security/AuthenticationContext.cs index 5ed4dafe3f1..b8719d5cc84 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContext.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContext.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api.Rights; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContextAuthorizationFilter.cs b/src/Tgstation.Server.Host/Security/AuthenticationContextAuthorizationFilter.cs index 562f49f443c..a3191770e46 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContextAuthorizationFilter.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContextAuthorizationFilter.cs @@ -5,6 +5,8 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContextClaimsTransformation.cs b/src/Tgstation.Server.Host/Security/AuthenticationContextClaimsTransformation.cs index 4f02bb0b0d7..9cf5de9de75 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContextClaimsTransformation.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContextClaimsTransformation.cs @@ -13,6 +13,8 @@ using Tgstation.Server.Api.Rights; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs b/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs index f39daaa9897..3be3bc8061c 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs @@ -11,6 +11,8 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/AuthorizationContextHubFilter.cs b/src/Tgstation.Server.Host/Security/AuthorizationContextHubFilter.cs index 38360cab9ba..a64f3d4cdbd 100644 --- a/src/Tgstation.Server.Host/Security/AuthorizationContextHubFilter.cs +++ b/src/Tgstation.Server.Host/Security/AuthorizationContextHubFilter.cs @@ -5,6 +5,8 @@ using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/CryptographySuite.cs b/src/Tgstation.Server.Host/Security/CryptographySuite.cs index d98e61c303f..8d2f6eeca52 100644 --- a/src/Tgstation.Server.Host/Security/CryptographySuite.cs +++ b/src/Tgstation.Server.Host/Security/CryptographySuite.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/IAuthenticationContext.cs b/src/Tgstation.Server.Host/Security/IAuthenticationContext.cs index 36abee2b2c5..39da97b00e3 100644 --- a/src/Tgstation.Server.Host/Security/IAuthenticationContext.cs +++ b/src/Tgstation.Server.Host/Security/IAuthenticationContext.cs @@ -1,6 +1,8 @@ using Tgstation.Server.Api.Rights; using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/IAuthenticationContextFactory.cs b/src/Tgstation.Server.Host/Security/IAuthenticationContextFactory.cs index cb70a50b18e..945b4e09add 100644 --- a/src/Tgstation.Server.Host/Security/IAuthenticationContextFactory.cs +++ b/src/Tgstation.Server.Host/Security/IAuthenticationContextFactory.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/ICryptographySuite.cs b/src/Tgstation.Server.Host/Security/ICryptographySuite.cs index 257a78f4d19..955fdac6ae4 100644 --- a/src/Tgstation.Server.Host/Security/ICryptographySuite.cs +++ b/src/Tgstation.Server.Host/Security/ICryptographySuite.cs @@ -1,5 +1,7 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/IIdentityCache.cs b/src/Tgstation.Server.Host/Security/IIdentityCache.cs index 0832189f83f..64fd3f39a97 100644 --- a/src/Tgstation.Server.Host/Security/IIdentityCache.cs +++ b/src/Tgstation.Server.Host/Security/IIdentityCache.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/IPermissionsUpdateNotifyee.cs b/src/Tgstation.Server.Host/Security/IPermissionsUpdateNotifyee.cs index 7a95f7f0760..dd313adc86e 100644 --- a/src/Tgstation.Server.Host/Security/IPermissionsUpdateNotifyee.cs +++ b/src/Tgstation.Server.Host/Security/IPermissionsUpdateNotifyee.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/ISystemIdentity.cs b/src/Tgstation.Server.Host/Security/ISystemIdentity.cs index bd63d784dea..e865b0345b2 100644 --- a/src/Tgstation.Server.Host/Security/ISystemIdentity.cs +++ b/src/Tgstation.Server.Host/Security/ISystemIdentity.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs b/src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs index 2568861e53a..de6e58d431e 100644 --- a/src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs +++ b/src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/ITokenFactory.cs b/src/Tgstation.Server.Host/Security/ITokenFactory.cs index bf9a70fab15..107965394c6 100644 --- a/src/Tgstation.Server.Host/Security/ITokenFactory.cs +++ b/src/Tgstation.Server.Host/Security/ITokenFactory.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/IdentityCache.cs b/src/Tgstation.Server.Host/Security/IdentityCache.cs index 0db031aba21..6c2a98b2009 100644 --- a/src/Tgstation.Server.Host/Security/IdentityCache.cs +++ b/src/Tgstation.Server.Host/Security/IdentityCache.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs b/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs index 7cc10664e5a..d7125b877fe 100644 --- a/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs +++ b/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs index 3195ec9dcf3..166ff85f277 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Security.OAuth { /// diff --git a/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs index 668a96240ff..0885546d117 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs @@ -16,6 +16,8 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Security.OAuth { /// diff --git a/src/Tgstation.Server.Host/Security/OAuth/GitHubOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/GitHubOAuthValidator.cs index 567887b06f4..d6ed38808b7 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/GitHubOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/GitHubOAuthValidator.cs @@ -10,6 +10,8 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Utils.GitHub; +#nullable disable + namespace Tgstation.Server.Host.Security.OAuth { /// diff --git a/src/Tgstation.Server.Host/Security/OAuth/IOAuthProviders.cs b/src/Tgstation.Server.Host/Security/OAuth/IOAuthProviders.cs index c8b8a7b1615..c7e9a062748 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/IOAuthProviders.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/IOAuthProviders.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Api.Models; +#nullable disable + namespace Tgstation.Server.Host.Security.OAuth { /// diff --git a/src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs index 7f3ca57287f..402fb5efe7a 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Api.Models; +#nullable disable + namespace Tgstation.Server.Host.Security.OAuth { /// diff --git a/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs index a0c8cdd0e2a..14382d58388 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Security.OAuth { /// diff --git a/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs index f4e61b4b5ce..1152398d6af 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Security.OAuth { /// diff --git a/src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs b/src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs index 7a562668ee8..7e0e1a308c0 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs @@ -10,6 +10,8 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Utils.GitHub; +#nullable disable + namespace Tgstation.Server.Host.Security.OAuth { /// diff --git a/src/Tgstation.Server.Host/Security/OAuth/OAuthTokenRequest.cs b/src/Tgstation.Server.Host/Security/OAuth/OAuthTokenRequest.cs index 9256092f101..2c7721f4aff 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/OAuthTokenRequest.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/OAuthTokenRequest.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Security.OAuth { /// diff --git a/src/Tgstation.Server.Host/Security/OAuth/TGForumsOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/TGForumsOAuthValidator.cs index c81a54ec738..36b213b6d98 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/TGForumsOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/TGForumsOAuthValidator.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Security.OAuth { /// diff --git a/src/Tgstation.Server.Host/Security/PosixSystemIdentity.cs b/src/Tgstation.Server.Host/Security/PosixSystemIdentity.cs index 67f0e3ac838..4f978e76d14 100644 --- a/src/Tgstation.Server.Host/Security/PosixSystemIdentity.cs +++ b/src/Tgstation.Server.Host/Security/PosixSystemIdentity.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/PosixSystemIdentityFactory.cs b/src/Tgstation.Server.Host/Security/PosixSystemIdentityFactory.cs index e85882665bf..876cca613e4 100644 --- a/src/Tgstation.Server.Host/Security/PosixSystemIdentityFactory.cs +++ b/src/Tgstation.Server.Host/Security/PosixSystemIdentityFactory.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Host.Models; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/TgsAuthorizeAttribute.cs b/src/Tgstation.Server.Host/Security/TgsAuthorizeAttribute.cs index 0fc4c11c1a0..a80205bb6e1 100644 --- a/src/Tgstation.Server.Host/Security/TgsAuthorizeAttribute.cs +++ b/src/Tgstation.Server.Host/Security/TgsAuthorizeAttribute.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api.Rights; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/TokenFactory.cs b/src/Tgstation.Server.Host/Security/TokenFactory.cs index cc18c3298a4..3a17f2ac865 100644 --- a/src/Tgstation.Server.Host/Security/TokenFactory.cs +++ b/src/Tgstation.Server.Host/Security/TokenFactory.cs @@ -12,6 +12,8 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/WindowsSystemIdentity.cs b/src/Tgstation.Server.Host/Security/WindowsSystemIdentity.cs index 28b6bbcec7a..f4ac20da190 100644 --- a/src/Tgstation.Server.Host/Security/WindowsSystemIdentity.cs +++ b/src/Tgstation.Server.Host/Security/WindowsSystemIdentity.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs b/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs index b677a56413d..56b04356518 100644 --- a/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs +++ b/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs @@ -12,6 +12,8 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Security { /// diff --git a/src/Tgstation.Server.Host/Server.cs b/src/Tgstation.Server.Host/Server.cs index e6ea8c04b1e..b57045078d5 100644 --- a/src/Tgstation.Server.Host/Server.cs +++ b/src/Tgstation.Server.Host/Server.cs @@ -14,6 +14,8 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Core; +#nullable disable + namespace Tgstation.Server.Host { /// diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index a466a97fb53..4b25e07fea2 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -17,6 +17,8 @@ using Tgstation.Server.Host.Setup; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host { /// diff --git a/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs b/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs index 21264d9277e..aaa785f4131 100644 --- a/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs +++ b/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs @@ -1,6 +1,8 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Setup { /// diff --git a/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs b/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs index f36d9526e78..25024af43db 100644 --- a/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs +++ b/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs @@ -1,5 +1,7 @@ using Microsoft.Extensions.Logging; +#nullable disable + namespace Tgstation.Server.Host.Setup { /// diff --git a/src/Tgstation.Server.Host/Setup/PostSetupServices.cs b/src/Tgstation.Server.Host/Setup/PostSetupServices.cs index c1ace340ec5..4fce4e6075e 100644 --- a/src/Tgstation.Server.Host/Setup/PostSetupServices.cs +++ b/src/Tgstation.Server.Host/Setup/PostSetupServices.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Setup { /// diff --git a/src/Tgstation.Server.Host/Setup/SetupApplication.cs b/src/Tgstation.Server.Host/Setup/SetupApplication.cs index 56c590ce7d0..ca4b64be58d 100644 --- a/src/Tgstation.Server.Host/Setup/SetupApplication.cs +++ b/src/Tgstation.Server.Host/Setup/SetupApplication.cs @@ -12,6 +12,8 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Setup { /// diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index b9671572b29..d4611f4465d 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -31,6 +31,8 @@ using YamlDotNet.Serialization; +#nullable disable + namespace Tgstation.Server.Host.Setup { /// diff --git a/src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs b/src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs index dd9c01b7830..8d3e198006c 100644 --- a/src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs +++ b/src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Swarm { /// diff --git a/src/Tgstation.Server.Host/Swarm/ISwarmService.cs b/src/Tgstation.Server.Host/Swarm/ISwarmService.cs index 9b863895402..c9e29bd0527 100644 --- a/src/Tgstation.Server.Host/Swarm/ISwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/ISwarmService.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Swarm { /// diff --git a/src/Tgstation.Server.Host/Swarm/ISwarmServiceController.cs b/src/Tgstation.Server.Host/Swarm/ISwarmServiceController.cs index 34babd945ba..9f875ce05bd 100644 --- a/src/Tgstation.Server.Host/Swarm/ISwarmServiceController.cs +++ b/src/Tgstation.Server.Host/Swarm/ISwarmServiceController.cs @@ -1,6 +1,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Swarm { /// diff --git a/src/Tgstation.Server.Host/Swarm/ISwarmUpdateAborter.cs b/src/Tgstation.Server.Host/Swarm/ISwarmUpdateAborter.cs index 8d69505f272..6cd79b99569 100644 --- a/src/Tgstation.Server.Host/Swarm/ISwarmUpdateAborter.cs +++ b/src/Tgstation.Server.Host/Swarm/ISwarmUpdateAborter.cs @@ -1,5 +1,7 @@ using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Swarm { /// diff --git a/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs b/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs index 988c60243ef..ec61a982bb3 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api; using Tgstation.Server.Host.Extensions.Converters; +#nullable disable + namespace Tgstation.Server.Host.Swarm { /// diff --git a/src/Tgstation.Server.Host/Swarm/SwarmRegistrationRequest.cs b/src/Tgstation.Server.Host/Swarm/SwarmRegistrationRequest.cs index cad1cebe279..93f5ed92db5 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmRegistrationRequest.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmRegistrationRequest.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Api.Models.Internal; +#nullable disable + namespace Tgstation.Server.Host.Swarm { /// diff --git a/src/Tgstation.Server.Host/Swarm/SwarmServersUpdateRequest.cs b/src/Tgstation.Server.Host/Swarm/SwarmServersUpdateRequest.cs index 61b60cc0242..2b3cdeaa23d 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmServersUpdateRequest.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmServersUpdateRequest.cs @@ -3,6 +3,8 @@ using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Swarm { /// diff --git a/src/Tgstation.Server.Host/Swarm/SwarmService.cs b/src/Tgstation.Server.Host/Swarm/SwarmService.cs index dc4dfa22515..d081050754b 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmService.cs @@ -26,6 +26,8 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Swarm { /// diff --git a/src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs b/src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs index 01b9f28d18f..3ebe8576e24 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Swarm { /// diff --git a/src/Tgstation.Server.Host/Swarm/SwarmUpdateRequest.cs b/src/Tgstation.Server.Host/Swarm/SwarmUpdateRequest.cs index 1da49cea3c3..a0d7b0fe5ca 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmUpdateRequest.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmUpdateRequest.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Swarm { /// diff --git a/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs b/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs index 88d1a3a627b..4d072772e5d 100644 --- a/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs +++ b/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Common; using Tgstation.Server.Common.Extensions; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/IAssemblyInformationProvider.cs b/src/Tgstation.Server.Host/System/IAssemblyInformationProvider.cs index 184dd9f60a1..7b092f8aeaa 100644 --- a/src/Tgstation.Server.Host/System/IAssemblyInformationProvider.cs +++ b/src/Tgstation.Server.Host/System/IAssemblyInformationProvider.cs @@ -2,6 +2,8 @@ using System.Net.Http.Headers; using System.Reflection; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/IPlatformIdentifier.cs b/src/Tgstation.Server.Host/System/IPlatformIdentifier.cs index 805b93b97d4..104bb0dc329 100644 --- a/src/Tgstation.Server.Host/System/IPlatformIdentifier.cs +++ b/src/Tgstation.Server.Host/System/IPlatformIdentifier.cs @@ -1,5 +1,7 @@ using System.Runtime.Versioning; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/IProcess.cs b/src/Tgstation.Server.Host/System/IProcess.cs index 8df102b2b2a..7b033f3e9d0 100644 --- a/src/Tgstation.Server.Host/System/IProcess.cs +++ b/src/Tgstation.Server.Host/System/IProcess.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/IProcessBase.cs b/src/Tgstation.Server.Host/System/IProcessBase.cs index 8fc0bd4484e..91feee546eb 100644 --- a/src/Tgstation.Server.Host/System/IProcessBase.cs +++ b/src/Tgstation.Server.Host/System/IProcessBase.cs @@ -1,6 +1,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/IProcessExecutor.cs b/src/Tgstation.Server.Host/System/IProcessExecutor.cs index 81593dbe37d..a0418aea0df 100644 --- a/src/Tgstation.Server.Host/System/IProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/IProcessExecutor.cs @@ -1,4 +1,6 @@ -namespace Tgstation.Server.Host.System +#nullable disable + +namespace Tgstation.Server.Host.System { /// /// For launching '. diff --git a/src/Tgstation.Server.Host/System/IProcessFeatures.cs b/src/Tgstation.Server.Host/System/IProcessFeatures.cs index abfaca6b7bf..8d4a9258c60 100644 --- a/src/Tgstation.Server.Host/System/IProcessFeatures.cs +++ b/src/Tgstation.Server.Host/System/IProcessFeatures.cs @@ -1,6 +1,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/NativeMethods.cs b/src/Tgstation.Server.Host/System/NativeMethods.cs index dc5046d1335..11f465fb139 100644 --- a/src/Tgstation.Server.Host/System/NativeMethods.cs +++ b/src/Tgstation.Server.Host/System/NativeMethods.cs @@ -2,6 +2,8 @@ using System.Runtime.InteropServices; using System.Text; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/PlatformIdentifier.cs b/src/Tgstation.Server.Host/System/PlatformIdentifier.cs index 22931b97ce1..6391932f1c9 100644 --- a/src/Tgstation.Server.Host/System/PlatformIdentifier.cs +++ b/src/Tgstation.Server.Host/System/PlatformIdentifier.cs @@ -1,6 +1,8 @@ using System.Runtime.InteropServices; using System.Runtime.Versioning; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs b/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs index b45c845fa4b..c1999c4545b 100644 --- a/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs +++ b/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs @@ -10,6 +10,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/PosixSignalHandler.cs b/src/Tgstation.Server.Host/System/PosixSignalHandler.cs index 693324d679b..5342f68d393 100644 --- a/src/Tgstation.Server.Host/System/PosixSignalHandler.cs +++ b/src/Tgstation.Server.Host/System/PosixSignalHandler.cs @@ -10,6 +10,8 @@ using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/Process.cs b/src/Tgstation.Server.Host/System/Process.cs index 003f3b12e4a..a505cee8781 100644 --- a/src/Tgstation.Server.Host/System/Process.cs +++ b/src/Tgstation.Server.Host/System/Process.cs @@ -9,6 +9,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index 7a00b31d10e..94e4af31b7b 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -9,6 +9,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/ProgramShutdownTokenSource.cs b/src/Tgstation.Server.Host/System/ProgramShutdownTokenSource.cs index fb68be4ac95..0f0dfb13b10 100644 --- a/src/Tgstation.Server.Host/System/ProgramShutdownTokenSource.cs +++ b/src/Tgstation.Server.Host/System/ProgramShutdownTokenSource.cs @@ -1,6 +1,8 @@ using System; using System.Threading; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/SystemDManager.cs b/src/Tgstation.Server.Host/System/SystemDManager.cs index 28fb4e4d25a..4e3b86972c7 100644 --- a/src/Tgstation.Server.Host/System/SystemDManager.cs +++ b/src/Tgstation.Server.Host/System/SystemDManager.cs @@ -11,6 +11,8 @@ using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Core; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs b/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs index 74964a5569f..7a5e82742f4 100644 --- a/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs +++ b/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs @@ -4,6 +4,8 @@ using Microsoft.Extensions.Logging; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs b/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs index 48924155719..c30bbb0359b 100644 --- a/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs +++ b/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs @@ -13,6 +13,8 @@ using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs b/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs index 41789aec8cc..c3a3b31d9b7 100644 --- a/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs +++ b/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs @@ -14,6 +14,8 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; +#nullable disable + namespace Tgstation.Server.Host.System { /// diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 9890be89d04..e293d810259 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -9,6 +9,7 @@ API1000;ASP0019 ClientApp/node_modules ClientApp/node_modules/.install-stamp + enable Linux ..\.. ../../build/uac_elevation_manifest.xml diff --git a/src/Tgstation.Server.Host/Transfer/FileDownloadProvider.cs b/src/Tgstation.Server.Host/Transfer/FileDownloadProvider.cs index 603e099c076..eee92cce021 100644 --- a/src/Tgstation.Server.Host/Transfer/FileDownloadProvider.cs +++ b/src/Tgstation.Server.Host/Transfer/FileDownloadProvider.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Api.Models; +#nullable disable + namespace Tgstation.Server.Host.Transfer { /// diff --git a/src/Tgstation.Server.Host/Transfer/FileTransferService.cs b/src/Tgstation.Server.Host/Transfer/FileTransferService.cs index fc0201b48dd..cbdc5284800 100644 --- a/src/Tgstation.Server.Host/Transfer/FileTransferService.cs +++ b/src/Tgstation.Server.Host/Transfer/FileTransferService.cs @@ -12,6 +12,8 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; +#nullable disable + namespace Tgstation.Server.Host.Transfer { /// diff --git a/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs b/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs index 9fe8250da5e..31a691b36ad 100644 --- a/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs +++ b/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs @@ -9,6 +9,8 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Transfer { /// diff --git a/src/Tgstation.Server.Host/Transfer/IFileTransferStreamHandler.cs b/src/Tgstation.Server.Host/Transfer/IFileTransferStreamHandler.cs index 75603c86841..f0ba7a396da 100644 --- a/src/Tgstation.Server.Host/Transfer/IFileTransferStreamHandler.cs +++ b/src/Tgstation.Server.Host/Transfer/IFileTransferStreamHandler.cs @@ -5,6 +5,8 @@ using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Transfer { /// diff --git a/src/Tgstation.Server.Host/Transfer/IFileTransferTicketProvider.cs b/src/Tgstation.Server.Host/Transfer/IFileTransferTicketProvider.cs index 1a13cb9f87d..98a2bfd9131 100644 --- a/src/Tgstation.Server.Host/Transfer/IFileTransferTicketProvider.cs +++ b/src/Tgstation.Server.Host/Transfer/IFileTransferTicketProvider.cs @@ -1,5 +1,7 @@ using Tgstation.Server.Api.Models.Response; +#nullable disable + namespace Tgstation.Server.Host.Transfer { /// diff --git a/src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs b/src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs index c1bd6e5725b..260be9573fb 100644 --- a/src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs +++ b/src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs @@ -2,6 +2,8 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Host.IO; +#nullable disable + namespace Tgstation.Server.Host.Transfer { /// diff --git a/src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs b/src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs index 973551e1d47..0bb43edf284 100644 --- a/src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs +++ b/src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// diff --git a/src/Tgstation.Server.Host/Utils/ApiHeadersProvider.cs b/src/Tgstation.Server.Host/Utils/ApiHeadersProvider.cs index 56aa2886195..95190dc500e 100644 --- a/src/Tgstation.Server.Host/Utils/ApiHeadersProvider.cs +++ b/src/Tgstation.Server.Host/Utils/ApiHeadersProvider.cs @@ -4,6 +4,8 @@ using Tgstation.Server.Api; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// diff --git a/src/Tgstation.Server.Host/Utils/AsyncDelayer.cs b/src/Tgstation.Server.Host/Utils/AsyncDelayer.cs index 79ffce18386..a435e38e9e7 100644 --- a/src/Tgstation.Server.Host/Utils/AsyncDelayer.cs +++ b/src/Tgstation.Server.Host/Utils/AsyncDelayer.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// diff --git a/src/Tgstation.Server.Host/Utils/FifoSemaphore.cs b/src/Tgstation.Server.Host/Utils/FifoSemaphore.cs index 7a4e200c9cb..099eea7d37c 100644 --- a/src/Tgstation.Server.Host/Utils/FifoSemaphore.cs +++ b/src/Tgstation.Server.Host/Utils/FifoSemaphore.cs @@ -3,6 +3,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// diff --git a/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs b/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs index 38fb72ffd68..40f76ecb572 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs @@ -9,6 +9,8 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Utils.GitHub { /// diff --git a/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs b/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs index 7429112712a..4e95f01820d 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs @@ -10,6 +10,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Utils.GitHub { /// diff --git a/src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs b/src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs index efa08d13bba..adb8d32c478 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Utils.GitHub { /// diff --git a/src/Tgstation.Server.Host/Utils/GitHub/IAuthenticatedGitHubService.cs b/src/Tgstation.Server.Host/Utils/GitHub/IAuthenticatedGitHubService.cs index 619bcead205..046ef67e773 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/IAuthenticatedGitHubService.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/IAuthenticatedGitHubService.cs @@ -3,6 +3,8 @@ using Octokit; +#nullable disable + namespace Tgstation.Server.Host.Utils.GitHub { /// diff --git a/src/Tgstation.Server.Host/Utils/GitHub/IGitHubClientFactory.cs b/src/Tgstation.Server.Host/Utils/GitHub/IGitHubClientFactory.cs index ec95fd16ab8..8ffea0fbd2b 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/IGitHubClientFactory.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/IGitHubClientFactory.cs @@ -1,5 +1,7 @@ using Octokit; +#nullable disable + namespace Tgstation.Server.Host.Utils.GitHub { /// diff --git a/src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs b/src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs index e2f338d77aa..b7bda78b31b 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs @@ -7,6 +7,8 @@ using Tgstation.Server.Host.Configuration; +#nullable disable + namespace Tgstation.Server.Host.Utils.GitHub { /// diff --git a/src/Tgstation.Server.Host/Utils/IApiHeadersProvider.cs b/src/Tgstation.Server.Host/Utils/IApiHeadersProvider.cs index 7de65834d3d..ea58c98199f 100644 --- a/src/Tgstation.Server.Host/Utils/IApiHeadersProvider.cs +++ b/src/Tgstation.Server.Host/Utils/IApiHeadersProvider.cs @@ -1,5 +1,7 @@ using Tgstation.Server.Api; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// diff --git a/src/Tgstation.Server.Host/Utils/IAsyncDelayer.cs b/src/Tgstation.Server.Host/Utils/IAsyncDelayer.cs index d47c5cbc626..38e738f5a2c 100644 --- a/src/Tgstation.Server.Host/Utils/IAsyncDelayer.cs +++ b/src/Tgstation.Server.Host/Utils/IAsyncDelayer.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// diff --git a/src/Tgstation.Server.Host/Utils/IPortAllocator.cs b/src/Tgstation.Server.Host/Utils/IPortAllocator.cs index 29d234ec62c..92a0f480b25 100644 --- a/src/Tgstation.Server.Host/Utils/IPortAllocator.cs +++ b/src/Tgstation.Server.Host/Utils/IPortAllocator.cs @@ -1,6 +1,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// diff --git a/src/Tgstation.Server.Host/Utils/OpenApiEnumVarNamesExtension.cs b/src/Tgstation.Server.Host/Utils/OpenApiEnumVarNamesExtension.cs index a81beb83393..75c71c75616 100644 --- a/src/Tgstation.Server.Host/Utils/OpenApiEnumVarNamesExtension.cs +++ b/src/Tgstation.Server.Host/Utils/OpenApiEnumVarNamesExtension.cs @@ -5,6 +5,8 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Writers; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// diff --git a/src/Tgstation.Server.Host/Utils/PortAllocator.cs b/src/Tgstation.Server.Host/Utils/PortAllocator.cs index 310cfbfe3da..546668e8d2e 100644 --- a/src/Tgstation.Server.Host/Utils/PortAllocator.cs +++ b/src/Tgstation.Server.Host/Utils/PortAllocator.cs @@ -14,6 +14,8 @@ using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.System; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// diff --git a/src/Tgstation.Server.Host/Utils/ReferenceCounter.cs b/src/Tgstation.Server.Host/Utils/ReferenceCounter.cs index 4351c65db66..19f8408eed3 100644 --- a/src/Tgstation.Server.Host/Utils/ReferenceCounter.cs +++ b/src/Tgstation.Server.Host/Utils/ReferenceCounter.cs @@ -1,5 +1,7 @@ using System; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// diff --git a/src/Tgstation.Server.Host/Utils/ReferenceCountingContainer.cs b/src/Tgstation.Server.Host/Utils/ReferenceCountingContainer.cs index 121411bd1da..2389435a6f2 100644 --- a/src/Tgstation.Server.Host/Utils/ReferenceCountingContainer.cs +++ b/src/Tgstation.Server.Host/Utils/ReferenceCountingContainer.cs @@ -1,6 +1,8 @@ using System; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// diff --git a/src/Tgstation.Server.Host/Utils/SemaphoreSlimContext.cs b/src/Tgstation.Server.Host/Utils/SemaphoreSlimContext.cs index 25f070cc4be..4339515859a 100644 --- a/src/Tgstation.Server.Host/Utils/SemaphoreSlimContext.cs +++ b/src/Tgstation.Server.Host/Utils/SemaphoreSlimContext.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// diff --git a/src/Tgstation.Server.Host/Utils/SignalR/ComprehensiveHubContext.cs b/src/Tgstation.Server.Host/Utils/SignalR/ComprehensiveHubContext.cs index 1f09be35719..27d842c3e11 100644 --- a/src/Tgstation.Server.Host/Utils/SignalR/ComprehensiveHubContext.cs +++ b/src/Tgstation.Server.Host/Utils/SignalR/ComprehensiveHubContext.cs @@ -11,6 +11,8 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; +#nullable disable + namespace Tgstation.Server.Host.Utils.SignalR { /// diff --git a/src/Tgstation.Server.Host/Utils/SignalR/ConnectionMappingHub.cs b/src/Tgstation.Server.Host/Utils/SignalR/ConnectionMappingHub.cs index 05e2eb8742e..86849018207 100644 --- a/src/Tgstation.Server.Host/Utils/SignalR/ConnectionMappingHub.cs +++ b/src/Tgstation.Server.Host/Utils/SignalR/ConnectionMappingHub.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Host.Security; +#nullable disable + namespace Tgstation.Server.Host.Utils.SignalR { /// diff --git a/src/Tgstation.Server.Host/Utils/SignalR/IConnectionMappedHubContext.cs b/src/Tgstation.Server.Host/Utils/SignalR/IConnectionMappedHubContext.cs index 101e8e599e6..bdf89de2776 100644 --- a/src/Tgstation.Server.Host/Utils/SignalR/IConnectionMappedHubContext.cs +++ b/src/Tgstation.Server.Host/Utils/SignalR/IConnectionMappedHubContext.cs @@ -8,6 +8,8 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; +#nullable disable + namespace Tgstation.Server.Host.Utils.SignalR { /// diff --git a/src/Tgstation.Server.Host/Utils/SignalR/IHubConnectionMapper.cs b/src/Tgstation.Server.Host/Utils/SignalR/IHubConnectionMapper.cs index 4521c87fcce..8163a737e4c 100644 --- a/src/Tgstation.Server.Host/Utils/SignalR/IHubConnectionMapper.cs +++ b/src/Tgstation.Server.Host/Utils/SignalR/IHubConnectionMapper.cs @@ -6,6 +6,8 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; +#nullable disable + namespace Tgstation.Server.Host.Utils.SignalR { /// diff --git a/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs b/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs index 8f8b0195bd7..aeaa86db108 100644 --- a/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs +++ b/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs @@ -20,6 +20,8 @@ using Tgstation.Server.Host.Controllers; using Tgstation.Server.Host.Security; +#nullable disable + namespace Tgstation.Server.Host.Utils { /// From 9daa97e123f39147bfd48d7b0ab0dcc3a4878df8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:40:56 -0500 Subject: [PATCH 203/717] Use a newer .NET 8 signature --- src/Tgstation.Server.Host/Core/CommandPipeManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Core/CommandPipeManager.cs b/src/Tgstation.Server.Host/Core/CommandPipeManager.cs index cd06a7a0738..d86e8ed69cf 100644 --- a/src/Tgstation.Server.Host/Core/CommandPipeManager.cs +++ b/src/Tgstation.Server.Host/Core/CommandPipeManager.cs @@ -100,7 +100,7 @@ protected override async Task ExecuteAsync(CancellationToken cancellationToken) while (!cancellationToken.IsCancellationRequested) { logger.LogTrace("Waiting to read command line..."); - var line = await streamReader.ReadLineAsync().WaitAsync(cancellationToken); + var line = await streamReader.ReadLineAsync(cancellationToken); logger?.LogInformation("Received pipe command: {command}", line); switch (line) From c6d17a1fa5c89e6ce7a0218992e816d9eceea4eb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 17:40:51 -0500 Subject: [PATCH 204/717] Nullify `Program` --- src/Tgstation.Server.Host/Program.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Program.cs b/src/Tgstation.Server.Host/Program.cs index fb5cf8a1c0b..8f0c5a3867f 100644 --- a/src/Tgstation.Server.Host/Program.cs +++ b/src/Tgstation.Server.Host/Program.cs @@ -11,8 +11,6 @@ using Tgstation.Server.Host.Properties; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host { /// @@ -46,7 +44,7 @@ public Program() public static async Task Main(string[] args) { // first arg is 100% always the update path, starting it otherwise is solely for debugging purposes - string updatePath = null; + string? updatePath = null; if (args.Length > 0) { var listArgs = new List(args); @@ -79,7 +77,7 @@ public static async Task Main(string[] args) /// The command line arguments, minus the . /// The path to extract server updates to be applied to. /// A resulting in the . - internal async ValueTask Main(string[] args, string updatePath) + internal async ValueTask Main(string[] args, string? updatePath) { try { From f8b0d62c601fb33347c03404850221d94e8fd247 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:03:40 -0500 Subject: [PATCH 205/717] Nullify `ServerFactory` --- src/Tgstation.Server.Host/IServerFactory.cs | 4 +--- src/Tgstation.Server.Host/Program.cs | 2 +- src/Tgstation.Server.Host/ServerFactory.cs | 7 +++---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Tgstation.Server.Host/IServerFactory.cs b/src/Tgstation.Server.Host/IServerFactory.cs index 937fee71846..b205d6b62e2 100644 --- a/src/Tgstation.Server.Host/IServerFactory.cs +++ b/src/Tgstation.Server.Host/IServerFactory.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host { /// @@ -24,6 +22,6 @@ public interface IServerFactory /// The directory in which to install server updates. /// The for the operation. /// A resulting in a new if it should be run, otherwise. - ValueTask CreateServer(string[] args, string updatePath, CancellationToken cancellationToken); + ValueTask CreateServer(string[] args, string? updatePath, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Program.cs b/src/Tgstation.Server.Host/Program.cs index 8f0c5a3867f..b23633b7dff 100644 --- a/src/Tgstation.Server.Host/Program.cs +++ b/src/Tgstation.Server.Host/Program.cs @@ -83,7 +83,7 @@ internal async ValueTask Main(string[] args, string? updatePath) { using var shutdownNotifier = new ProgramShutdownTokenSource(); var cancellationToken = shutdownNotifier.Token; - IServer server; + IServer? server; try { server = await ServerFactory.CreateServer( diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index 4b25e07fea2..f92298da10d 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -17,8 +17,6 @@ using Tgstation.Server.Host.Setup; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host { /// @@ -53,7 +51,7 @@ internal ServerFactory(IAssemblyInformationProvider assemblyInformationProvider, /// // TODO: Decomplexify #pragma warning disable CA1506 - public async ValueTask CreateServer(string[] args, string updatePath, CancellationToken cancellationToken) + public async ValueTask CreateServer(string[] args, string? updatePath, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(args); @@ -98,7 +96,8 @@ IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateD #if !NET8_0 #error Validate this monstrosity works on current .NET #endif - IConfigurationSource cmdLineConfig, baseYmlConfig, environmentYmlConfig; + IConfigurationSource? cmdLineConfig; + IConfigurationSource baseYmlConfig, environmentYmlConfig; if (args.Length == 0) { cmdLineConfig = null; From 4ff13f05f817cc465d11a4380baab493f01f3231 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:33:04 -0500 Subject: [PATCH 206/717] Nullify `Server` Not a fan of this one --- src/Tgstation.Server.Host/Server.cs | 45 ++++++++++++++++------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/Tgstation.Server.Host/Server.cs b/src/Tgstation.Server.Host/Server.cs index b57045078d5..3e43fe83f36 100644 --- a/src/Tgstation.Server.Host/Server.cs +++ b/src/Tgstation.Server.Host/Server.cs @@ -14,8 +14,6 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Core; -#nullable disable - namespace Tgstation.Server.Host { /// @@ -38,7 +36,7 @@ sealed class Server : IServer, IServerControl /// /// The of the running server. /// - internal IHost Host { get; private set; } + internal IHost? Host { get; private set; } /// /// The for the . @@ -53,7 +51,7 @@ sealed class Server : IServer, IServerControl /// /// The absolute path to install updates to. /// - readonly string updatePath; + readonly string? updatePath; /// /// for certain restart related operations. @@ -63,27 +61,27 @@ sealed class Server : IServer, IServerControl /// /// The for the . /// - ILogger logger; + ILogger? logger; /// /// The for the . /// - GeneralConfiguration generalConfiguration; + GeneralConfiguration? generalConfiguration; /// /// The for the . /// - CancellationTokenSource cancellationTokenSource; + CancellationTokenSource? cancellationTokenSource; /// /// The to propagate when the server terminates. /// - Exception propagatedException; + Exception? propagatedException; /// /// The that is used for asynchronously updating the server. /// - Task updateTask; + Task? updateTask; /// /// If the server is being shut down or restarted. @@ -100,7 +98,7 @@ sealed class Server : IServer, IServerControl /// /// The value of . /// The value of . - public Server(IHostBuilder hostBuilder, string updatePath) + public Server(IHostBuilder hostBuilder, string? updatePath) { this.hostBuilder = hostBuilder ?? throw new ArgumentNullException(nameof(hostBuilder)); this.updatePath = updatePath; @@ -109,15 +107,17 @@ public Server(IHostBuilder hostBuilder, string updatePath) restartHandlers = new List(); restartLock = new object(); + logger = null; } /// public async ValueTask Run(CancellationToken cancellationToken) { + var updateDirectory = updatePath != null ? Path.GetDirectoryName(updatePath) : null; using (cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) - using (var fsWatcher = updatePath != null ? new FileSystemWatcher(Path.GetDirectoryName(updatePath)) : null) + using (var fsWatcher = updateDirectory != null ? new FileSystemWatcher(updateDirectory) : null) { - if (updatePath != null) + if (fsWatcher != null) { // If ever there is a NECESSARY update to the Host Watchdog, change this to use a pipe // I don't know why I'm only realizing this in 2023 when this is 2019 code @@ -130,9 +130,10 @@ public async ValueTask Run(CancellationToken cancellationToken) try { using (Host = hostBuilder.Build()) + { + logger = Host.Services.GetRequiredService>(); try { - logger = Host.Services.GetRequiredService>(); using (cancellationToken.Register(() => logger.LogInformation("Server termination requested!"))) { var generalConfigurationOptions = Host.Services.GetRequiredService>(); @@ -156,6 +157,7 @@ public async ValueTask Run(CancellationToken cancellationToken) { logger = null; } + } } finally { @@ -174,6 +176,7 @@ public bool TryStartUpdate(IServerUpdateExecutor updateExecutor, Version newVers CheckSanity(true); + var logger = this.logger!; logger.LogTrace("Begin ApplyUpdate..."); CancellationToken criticalCancellationToken; @@ -222,6 +225,7 @@ public IRestartRegistration RegisterForRestart(IRestartHandler handler) CheckSanity(false); + var logger = this.logger!; lock (restartLock) if (!shutdownInProgress) { @@ -272,7 +276,7 @@ void CheckSanity(bool checkWatchdog) /// Re-throw if it exists. /// /// An existing that should be thrown as well, but not by itself. - void CheckExceptionPropagation(Exception otherException) + void CheckExceptionPropagation(Exception? otherException) { if (propagatedException == null) return; @@ -291,12 +295,13 @@ void CheckExceptionPropagation(Exception otherException) /// If the host watchdog is required for this "restart". /// If the restart should wait for extremely long running tasks to complete (Like the current DreamDaemon world). /// A representing the running operation. - async ValueTask RestartImpl(Version newVersion, Exception exception, bool requireWatchdog, bool completeAsap) + async ValueTask RestartImpl(Version? newVersion, Exception? exception, bool requireWatchdog, bool completeAsap) { CheckSanity(requireWatchdog); // if the watchdog isn't required and there's no issue, this is just a graceful shutdown bool isGracefulShutdown = !requireWatchdog && exception == null; + var logger = this.logger!; logger.LogTrace( "Begin {restartType}...", isGracefulShutdown @@ -324,8 +329,8 @@ async ValueTask RestartImpl(Version newVersion, Exception exception, bool requir using var cts = new CancellationTokenSource( TimeSpan.FromMinutes( giveHandlersTimeToWaitAround - ? generalConfiguration.ShutdownTimeoutMinutes - : generalConfiguration.RestartTimeoutMinutes)); + ? generalConfiguration!.ShutdownTimeoutMinutes + : generalConfiguration!.RestartTimeoutMinutes)); var cancellationToken = cts.Token; try { @@ -368,7 +373,7 @@ void WatchForShutdownFileCreation(object sender, FileSystemEventArgs eventArgs) logger?.LogTrace("FileSystemWatcher triggered."); // TODO: Refactor this to not use System.IO function here. - if (eventArgs.FullPath == Path.GetFullPath(updatePath) && File.Exists(eventArgs.FullPath)) + if (eventArgs.FullPath == Path.GetFullPath(updatePath!) && File.Exists(eventArgs.FullPath)) { logger?.LogInformation("Host watchdog appears to be requesting server termination!"); lock (restartLock) @@ -392,8 +397,8 @@ void WatchForShutdownFileCreation(object sender, FileSystemEventArgs eventArgs) void StopServerImmediate() { shutdownInProgress = true; - logger.LogDebug("Stopping host..."); - cancellationTokenSource.Cancel(); + logger!.LogDebug("Stopping host..."); + cancellationTokenSource!.Cancel(); } } } From 8bdb8a4575e54170d85e81dfe2dbb8e3fbf4d049 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:35:34 -0500 Subject: [PATCH 207/717] Nullify `Application` That was easy --- src/Tgstation.Server.Host/Core/Application.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 404655f3796..a4deff4806e 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -63,8 +63,6 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Core { /// @@ -81,7 +79,7 @@ public sealed class Application : SetupApplication /// /// The for the . /// - ITokenFactory tokenFactory; + ITokenFactory? tokenFactory; /// /// Create the default . @@ -537,7 +535,7 @@ public void Configure( applicationBuilder.UseRouting(); // Set up CORS based on configuration if necessary - Action corsBuilder = null; + Action? corsBuilder = null; if (controlPanelConfiguration.AllowAnyOrigin) { logger.LogTrace("Access-Control-Allow-Origin: *"); @@ -621,9 +619,9 @@ void ConfigureAuthenticationPipeline(IServiceCollection services) // return provider.GetRequiredService().CurrentAuthenticationContext // But M$ said // https://stackoverflow.com/questions/56792917/scoped-services-in-asp-net-core-with-signalr-hubs - services.AddScoped(provider => provider + services.AddScoped(provider => (provider .GetRequiredService() - .HttpContext + .HttpContext ?? throw new InvalidOperationException($"Unable to resolve {nameof(IAuthenticationContext)} due to no HttpContext being available!")) .RequestServices .GetRequiredService() .CurrentAuthenticationContext); From 68792b1cdf34bad5691a4a3761f4e21d2bb6bf81 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:43:20 -0500 Subject: [PATCH 208/717] Nullify `CommandPipeManager` --- .../Core/CommandPipeManager.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/CommandPipeManager.cs b/src/Tgstation.Server.Host/Core/CommandPipeManager.cs index 798b7db57ca..fce8fa9ccdb 100644 --- a/src/Tgstation.Server.Host/Core/CommandPipeManager.cs +++ b/src/Tgstation.Server.Host/Core/CommandPipeManager.cs @@ -13,8 +13,6 @@ using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Core { /// @@ -98,13 +96,13 @@ protected override async Task ExecuteAsync(CancellationToken cancellationToken) try { - using var streamReader = new StreamReader(commandPipeClient, Encoding.UTF8, leaveOpen: true); + using var streamReader = new StreamReader(commandPipeClient!, Encoding.UTF8, leaveOpen: true); while (!cancellationToken.IsCancellationRequested) { logger.LogTrace("Waiting to read command line..."); var line = await streamReader.ReadLineAsync().WaitAsync(cancellationToken); - logger?.LogInformation("Received pipe command: {command}", line); + logger.LogInformation("Received pipe command: {command}", line); switch (line) { case PipeCommands.CommandStop: @@ -120,22 +118,22 @@ protected override async Task ExecuteAsync(CancellationToken cancellationToken) logger.LogError("Read null from pipe!"); return; default: - logger?.LogWarning("Unrecognized pipe command: {command}", line); + logger.LogWarning("Unrecognized pipe command: {command}", line); break; } } } catch (OperationCanceledException ex) { - logger?.LogTrace(ex, "Command read task cancelled!"); + logger.LogTrace(ex, "Command read task cancelled!"); } catch (Exception ex) { - logger?.LogError(ex, "Command read task errored!"); + logger.LogError(ex, "Command read task errored!"); } finally { - logger?.LogTrace("Command read task exiting..."); + logger.LogTrace("Command read task exiting..."); } } } From 010c0e07781a6a5c6f39b732b26d2e0cdd56b54e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:44:27 -0500 Subject: [PATCH 209/717] Nullify `IRestartHandler` --- src/Tgstation.Server.Host/Core/IRestartHandler.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/IRestartHandler.cs b/src/Tgstation.Server.Host/Core/IRestartHandler.cs index 4db9ad18c3d..b663ae5d22c 100644 --- a/src/Tgstation.Server.Host/Core/IRestartHandler.cs +++ b/src/Tgstation.Server.Host/Core/IRestartHandler.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Core { /// @@ -18,6 +16,6 @@ public interface IRestartHandler /// If the should aim to complete the returned from this function ASAP. /// The for the operation. /// A representing the running operation. - ValueTask HandleRestart(Version updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken); + ValueTask HandleRestart(Version? updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken); } } From 6092baf408e20be271398d6e8bac9a35f47516d7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:44:59 -0500 Subject: [PATCH 210/717] Nullify `IServerControl` --- src/Tgstation.Server.Host/Core/IServerControl.cs | 4 +--- src/Tgstation.Server.Host/Server.cs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/IServerControl.cs b/src/Tgstation.Server.Host/Core/IServerControl.cs index 8eca773ecb9..92bbfe75f50 100644 --- a/src/Tgstation.Server.Host/Core/IServerControl.cs +++ b/src/Tgstation.Server.Host/Core/IServerControl.cs @@ -1,8 +1,6 @@ using System; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Core { /// @@ -53,6 +51,6 @@ public interface IServerControl /// /// The to propagate to the watchdog if any. /// A representing the running operation. - ValueTask Die(Exception exception); + ValueTask Die(Exception? exception); } } diff --git a/src/Tgstation.Server.Host/Server.cs b/src/Tgstation.Server.Host/Server.cs index 3e43fe83f36..b1432bc8164 100644 --- a/src/Tgstation.Server.Host/Server.cs +++ b/src/Tgstation.Server.Host/Server.cs @@ -250,7 +250,7 @@ public IRestartRegistration RegisterForRestart(IRestartHandler handler) public ValueTask GracefulShutdown(bool detach) => RestartImpl(null, null, false, detach); /// - public ValueTask Die(Exception exception) + public ValueTask Die(Exception? exception) { if (exception != null) return RestartImpl(null, exception, false, true); From 2a1f3179f5d64d77cd63093b231e15628b40b9cb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:46:41 -0500 Subject: [PATCH 211/717] Nullify `IServerUpdateExecutor` --- src/Tgstation.Server.Host/Core/IServerUpdateExecutor.cs | 2 -- src/Tgstation.Server.Host/Server.cs | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/IServerUpdateExecutor.cs b/src/Tgstation.Server.Host/Core/IServerUpdateExecutor.cs index 9a1ea2d0119..c2bf6f2090c 100644 --- a/src/Tgstation.Server.Host/Core/IServerUpdateExecutor.cs +++ b/src/Tgstation.Server.Host/Core/IServerUpdateExecutor.cs @@ -1,8 +1,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Core { /// diff --git a/src/Tgstation.Server.Host/Server.cs b/src/Tgstation.Server.Host/Server.cs index b1432bc8164..b832be6e873 100644 --- a/src/Tgstation.Server.Host/Server.cs +++ b/src/Tgstation.Server.Host/Server.cs @@ -176,6 +176,9 @@ public bool TryStartUpdate(IServerUpdateExecutor updateExecutor, Version newVers CheckSanity(true); + if (updatePath == null) + throw new InvalidOperationException("Tried to start update when server was initialized without an updatePath set!"); + var logger = this.logger!; logger.LogTrace("Begin ApplyUpdate..."); From c106e06c256f54b0f8d5e9de21dcc7b2fb178d05 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:47:10 -0500 Subject: [PATCH 212/717] Nullify `IServerUpdateInitiator` --- src/Tgstation.Server.Host/Core/IServerUpdateInitiator.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/IServerUpdateInitiator.cs b/src/Tgstation.Server.Host/Core/IServerUpdateInitiator.cs index f9af6f34de7..35aaa4037b9 100644 --- a/src/Tgstation.Server.Host/Core/IServerUpdateInitiator.cs +++ b/src/Tgstation.Server.Host/Core/IServerUpdateInitiator.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Core { /// @@ -20,6 +18,6 @@ public interface IServerUpdateInitiator /// The TGS to update to. /// The for the operation. /// A resulting in the . - ValueTask InitiateUpdate(IFileStreamProvider fileStreamProvider, Version version, CancellationToken cancellationToken); + ValueTask InitiateUpdate(IFileStreamProvider? fileStreamProvider, Version version, CancellationToken cancellationToken); } } From 5b2bb10d9142f5fc55ef92055bc0e97c5f7d08a1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:47:50 -0500 Subject: [PATCH 213/717] Nullify `IServerUpdater` --- src/Tgstation.Server.Host/Core/IServerUpdater.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/IServerUpdater.cs b/src/Tgstation.Server.Host/Core/IServerUpdater.cs index de0e38b67d8..4a7a7c0519a 100644 --- a/src/Tgstation.Server.Host/Core/IServerUpdater.cs +++ b/src/Tgstation.Server.Host/Core/IServerUpdater.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Swarm; -#nullable disable - namespace Tgstation.Server.Host.Core { /// @@ -22,6 +20,6 @@ interface IServerUpdater /// The TGS to update to. /// The for the operation. /// A resulting in the . - ValueTask BeginUpdate(ISwarmService swarmService, IFileStreamProvider fileStreamProvider, Version version, CancellationToken cancellationToken); + ValueTask BeginUpdate(ISwarmService swarmService, IFileStreamProvider? fileStreamProvider, Version version, CancellationToken cancellationToken); } } From 45a8371acfce0d9b4eca79e2c0da7ff8d7a2a9af Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:54:18 -0500 Subject: [PATCH 214/717] Nullify `RestartRegistration` --- src/Tgstation.Server.Host/Core/RestartRegistration.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/RestartRegistration.cs b/src/Tgstation.Server.Host/Core/RestartRegistration.cs index d685fe590b4..8f4ab937d6b 100644 --- a/src/Tgstation.Server.Host/Core/RestartRegistration.cs +++ b/src/Tgstation.Server.Host/Core/RestartRegistration.cs @@ -1,7 +1,5 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.Core { /// @@ -10,13 +8,13 @@ sealed class RestartRegistration : IRestartRegistration /// /// The . /// - readonly Action onDispose; + readonly Action? onDispose; /// /// Initializes a new instance of the class. /// /// The value of . - public RestartRegistration(Action onDispose) + public RestartRegistration(Action? onDispose) { this.onDispose = onDispose; } From 34f47edbabd893a3ddb70eb38beda855c4a852a0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:56:26 -0500 Subject: [PATCH 215/717] Nullify `ServerPortProvider` --- .../Core/ServerPortProivder.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/ServerPortProivder.cs b/src/Tgstation.Server.Host/Core/ServerPortProivder.cs index 0b97105c43f..a3f39a4ab82 100644 --- a/src/Tgstation.Server.Host/Core/ServerPortProivder.cs +++ b/src/Tgstation.Server.Host/Core/ServerPortProivder.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Core { /// @@ -36,18 +34,17 @@ public ServerPortProivder( generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); ArgumentNullException.ThrowIfNull(configuration); + var usingDefaultPort = generalConfiguration.ApiPort == default; + if (!usingDefaultPort) + return; + var httpEndpoint = configuration .GetSection("Kestrel") .GetSection("EndPoints") .GetSection("Http") .GetSection("Url") - .Value; - - if (generalConfiguration.ApiPort == default && httpEndpoint == null) - throw new InvalidOperationException("Missing required configuration option General:ApiPort!"); - - if (generalConfiguration.ApiPort != default) - return; + .Value + ?? throw new InvalidOperationException("Missing required configuration option General:ApiPort!"); logger.LogWarning("The \"Kestrel\" configuration section is deprecated! Please set your API port using the \"General:ApiPort\" configuration option!"); From 29fdb487e2b638d21ee18a5838e6c8432e92671a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:56:56 -0500 Subject: [PATCH 216/717] Nullify `ServerUpdateInitiator` --- src/Tgstation.Server.Host/Core/ServerUpdateInitiator.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/ServerUpdateInitiator.cs b/src/Tgstation.Server.Host/Core/ServerUpdateInitiator.cs index 0819b4ddd5a..fc1dc084cc7 100644 --- a/src/Tgstation.Server.Host/Core/ServerUpdateInitiator.cs +++ b/src/Tgstation.Server.Host/Core/ServerUpdateInitiator.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Swarm; -#nullable disable - namespace Tgstation.Server.Host.Core { /// @@ -34,7 +32,7 @@ public ServerUpdateInitiator(ISwarmService swarmService, IServerUpdater serverUp } /// - public ValueTask InitiateUpdate(IFileStreamProvider fileStreamProvider, Version version, CancellationToken cancellationToken) + public ValueTask InitiateUpdate(IFileStreamProvider? fileStreamProvider, Version version, CancellationToken cancellationToken) => serverUpdater.BeginUpdate(swarmService, fileStreamProvider, version, cancellationToken); } } From eae3a3a5ec09fd8e94f749a087686f690cdafc1d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:57:16 -0500 Subject: [PATCH 217/717] Nullify `ServerUpdateOperation` --- src/Tgstation.Server.Host/Core/ServerUpdateOperation.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/ServerUpdateOperation.cs b/src/Tgstation.Server.Host/Core/ServerUpdateOperation.cs index 1e673f82395..f14d85ec752 100644 --- a/src/Tgstation.Server.Host/Core/ServerUpdateOperation.cs +++ b/src/Tgstation.Server.Host/Core/ServerUpdateOperation.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Swarm; -#nullable disable - namespace Tgstation.Server.Host.Core { /// From 0bd4eaf9db46268e9cb5ac26ecb26a9d556477ae Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:59:40 -0500 Subject: [PATCH 218/717] Nullify `ServerUpdater` --- .../Core/ServerUpdater.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/ServerUpdater.cs b/src/Tgstation.Server.Host/Core/ServerUpdater.cs index be3b9f033c6..8c9d9681687 100644 --- a/src/Tgstation.Server.Host/Core/ServerUpdater.cs +++ b/src/Tgstation.Server.Host/Core/ServerUpdater.cs @@ -11,8 +11,6 @@ using Tgstation.Server.Host.Swarm; using Tgstation.Server.Host.Utils.GitHub; -#nullable disable - namespace Tgstation.Server.Host.Core { /// @@ -61,7 +59,7 @@ sealed class ServerUpdater : IServerUpdater, IServerUpdateExecutor /// /// for an in-progress update operation. /// - ServerUpdateOperation serverUpdateOperation; + ServerUpdateOperation? serverUpdateOperation; /// /// Initializes a new instance of the class. @@ -94,7 +92,7 @@ public ServerUpdater( } /// - public async ValueTask BeginUpdate(ISwarmService swarmService, IFileStreamProvider fileStreamProvider, Version version, CancellationToken cancellationToken) + public async ValueTask BeginUpdate(ISwarmService swarmService, IFileStreamProvider? fileStreamProvider, Version version, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(swarmService); @@ -203,7 +201,7 @@ async ValueTask TryAbort(Exception exception) { try { - await serverUpdateOperation.SwarmService.AbortUpdate(); + await serverUpdateOperation!.SwarmService.AbortUpdate(); } catch (Exception e2) { @@ -216,11 +214,11 @@ async ValueTask TryAbort(Exception exception) /// /// The directory the server update is initially extracted to. /// The for the operation. - /// A resulting in containing a new based on the of and if it needs to be kept active until the swarm commit. + /// A resulting in containing a new based on the of and if it needs to be kept active until the swarm commit. If , the update failed to prepare. /// Requires to be populated. - async ValueTask> PrepareUpdateClearStagingAndBufferStream(string stagingDirectory, CancellationToken cancellationToken) + async ValueTask?> PrepareUpdateClearStagingAndBufferStream(string stagingDirectory, CancellationToken cancellationToken) { - await using var fileStreamProvider = serverUpdateOperation.FileStreamProvider; + await using var fileStreamProvider = serverUpdateOperation!.FileStreamProvider; var bufferedStream = new BufferedFileStreamProvider( await fileStreamProvider.GetResult(cancellationToken)); @@ -278,12 +276,12 @@ async ValueTask> PrepareUpdateClearStagi /// A resulting in the . async ValueTask BeginUpdateImpl( ISwarmService swarmService, - IFileStreamProvider fileStreamProvider, + IFileStreamProvider? fileStreamProvider, Version newVersion, bool recursed, CancellationToken cancellationToken) { - ServerUpdateOperation ourUpdateOperation = null; + ServerUpdateOperation? ourUpdateOperation = null; try { if (fileStreamProvider == null) From f885a4e292d2bb90c88bd990316f2d86f4498620 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:00:41 -0500 Subject: [PATCH 219/717] Nullify `ControlPanelConfiguration` --- .../Configuration/ControlPanelConfiguration.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/ControlPanelConfiguration.cs b/src/Tgstation.Server.Host/Configuration/ControlPanelConfiguration.cs index 437a420495e..12da65e3122 100644 --- a/src/Tgstation.Server.Host/Configuration/ControlPanelConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/ControlPanelConfiguration.cs @@ -1,7 +1,5 @@ using System.Collections.Generic; -#nullable disable - namespace Tgstation.Server.Host.Configuration { /// @@ -38,16 +36,16 @@ public bool Enable /// /// The channel to retrieve the webpanel from. "local" uses the bundled version. /// - public string Channel { get; set; } + public string? Channel { get; set; } /// /// The public path to the TGS control panel from a wider network. /// - public string PublicPath { get; set; } + public string? PublicPath { get; set; } /// /// Origins allowed for CORS requests. /// - public ICollection AllowedOrigins { get; set; } + public ICollection? AllowedOrigins { get; set; } } } From 954b421a5dad866bea90d3bb6b14377bb4e1a500 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:01:35 -0500 Subject: [PATCH 220/717] Nullify `DatabaseConfiguration` --- .../Configuration/DatabaseConfiguration.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs b/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs index 51e78a2494c..ea699cd4ada 100644 --- a/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/DatabaseConfiguration.cs @@ -1,8 +1,6 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; -#nullable disable - namespace Tgstation.Server.Host.Configuration { /// @@ -29,7 +27,7 @@ public sealed class DatabaseConfiguration /// /// The connection string for the database. /// - public string ConnectionString { get; set; } + public string? ConnectionString { get; set; } /// /// If the database should be deleted on application startup. Should not be used in production!. @@ -39,6 +37,6 @@ public sealed class DatabaseConfiguration /// /// The form of the of the target server. /// - public string ServerVersion { get; set; } + public string? ServerVersion { get; set; } } } From 174d0ecf1feef2c92b6ab729846ebc2e451fcbfa Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:03:16 -0500 Subject: [PATCH 221/717] Nullify `ElasticsearchConfiguration` --- .../Configuration/ElasticsearchConfiguration.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/ElasticsearchConfiguration.cs b/src/Tgstation.Server.Host/Configuration/ElasticsearchConfiguration.cs index 424d746a67a..a99f3b03e8b 100644 --- a/src/Tgstation.Server.Host/Configuration/ElasticsearchConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/ElasticsearchConfiguration.cs @@ -1,9 +1,7 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.Configuration - { +{ /// /// Configuration options pertaining to elasticsearch log storage. /// @@ -22,16 +20,16 @@ public sealed class ElasticsearchConfiguration /// /// The host of the elasticsearch endpoint. /// - public Uri Host { get; set; } + public Uri? Host { get; set; } /// /// Username for elasticsearch. /// - public string Username { get; set; } + public string? Username { get; set; } /// /// Password for elasticsearch. /// - public string Password { get; set; } + public string? Password { get; set; } } } From da5adac6682009c8f86917310be795cae3e38e2a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:04:02 -0500 Subject: [PATCH 222/717] Nullify `FileLoggingConfiguration` --- .../Configuration/FileLoggingConfiguration.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs b/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs index 6d73d95ad9c..61dfe777c7e 100644 --- a/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Configuration { /// @@ -24,7 +22,7 @@ public sealed class FileLoggingConfiguration /// /// Where log files are stored. /// - public string Directory { get; set; } + public string? Directory { get; set; } /// /// If file logging is disabled. From e8a1009a46703f8ceb1c4931f98c8a0d6dbe849a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:06:00 -0500 Subject: [PATCH 223/717] Nullify `GeneralConfiguration` --- .../Configuration/GeneralConfiguration.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs index a21f796dc7f..ce32b46a0f5 100644 --- a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs @@ -11,8 +11,6 @@ using YamlDotNet.Serialization; -#nullable disable - namespace Tgstation.Server.Host.Configuration { /// @@ -83,7 +81,7 @@ public sealed class GeneralConfiguration : ServerInformationBase /// /// The the file says it is. /// - public Version ConfigVersion { get; set; } + public Version? ConfigVersion { get; set; } /// /// The port the TGS API listens on. @@ -93,7 +91,7 @@ public sealed class GeneralConfiguration : ServerInformationBase /// /// A GitHub personal access token to use for bypassing rate limits on requests. Requires no scopes. /// - public string GitHubAccessToken { get; set; } + public string? GitHubAccessToken { get; set; } /// /// The . From a3b81f83770e7062ff202fdb48fe2be135c515b6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:08:31 -0500 Subject: [PATCH 224/717] Nullify `InternalConfiguration` --- .../Configuration/InternalConfiguration.cs | 12 +++++------- src/Tgstation.Server.Host/Core/CommandPipeManager.cs | 10 ++++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs b/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs index 315cdad35c6..832041debac 100644 --- a/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs @@ -1,6 +1,4 @@ -#nullable disable - -namespace Tgstation.Server.Host.Configuration +namespace Tgstation.Server.Host.Configuration { /// /// Unstable configuration options used internally by TGS. @@ -15,12 +13,12 @@ public sealed class InternalConfiguration /// /// The name of the pipe opened by the host watchdog for sending commands, if any. /// - public string CommandPipe { get; set; } + public string? CommandPipe { get; set; } /// /// The name of the pipe opened by the host watchdog for receiving commands, if any. /// - public string ReadyPipe { get; set; } + public string? ReadyPipe { get; set; } /// /// If the server is running under SystemD. @@ -30,7 +28,7 @@ public sealed class InternalConfiguration /// /// The base path for the app settings configuration files. /// - public string AppSettingsBasePath { get; set; } + public string? AppSettingsBasePath { get; set; } /// /// Coerce the to select . @@ -40,6 +38,6 @@ public sealed class InternalConfiguration /// /// Generate default configuration using the given default password. /// - public string MariaDBDefaultRootPassword { get; set; } + public string? MariaDBDefaultRootPassword { get; set; } } } diff --git a/src/Tgstation.Server.Host/Core/CommandPipeManager.cs b/src/Tgstation.Server.Host/Core/CommandPipeManager.cs index fce8fa9ccdb..298e6c28ca5 100644 --- a/src/Tgstation.Server.Host/Core/CommandPipeManager.cs +++ b/src/Tgstation.Server.Host/Core/CommandPipeManager.cs @@ -65,22 +65,24 @@ protected override async Task ExecuteAsync(CancellationToken cancellationToken) logger.LogTrace("Starting..."); // grab both pipes asap so we can close them on error - var supportsPipeCommands = !String.IsNullOrWhiteSpace(internalConfiguration.CommandPipe); + var commandPipe = internalConfiguration.CommandPipe; + var supportsPipeCommands = !String.IsNullOrWhiteSpace(commandPipe); await using var commandPipeClient = supportsPipeCommands ? new AnonymousPipeClientStream( PipeDirection.In, - internalConfiguration.CommandPipe) + commandPipe!) : null; if (!supportsPipeCommands) logger.LogDebug("No command pipe name specified in configuration"); - var supportsReadyNotification = !String.IsNullOrWhiteSpace(internalConfiguration.ReadyPipe); + var readyPipe = internalConfiguration.ReadyPipe; + var supportsReadyNotification = !String.IsNullOrWhiteSpace(readyPipe); if (supportsReadyNotification) { await using var readyPipeClient = new AnonymousPipeClientStream( PipeDirection.Out, - internalConfiguration.ReadyPipe); + readyPipe!); logger.LogTrace("Waiting to send ready notification..."); await instanceManager.Ready.WaitAsync(cancellationToken); From a143006c8a498efc6f5063e443bfcc9d53b601e9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:09:17 -0500 Subject: [PATCH 225/717] Nullify `OAuthConfiguration` --- .../Configuration/OAuthConfiguration.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/OAuthConfiguration.cs b/src/Tgstation.Server.Host/Configuration/OAuthConfiguration.cs index ae1005b00e6..2d4c7811028 100644 --- a/src/Tgstation.Server.Host/Configuration/OAuthConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/OAuthConfiguration.cs @@ -1,7 +1,5 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.Configuration { /// @@ -12,16 +10,16 @@ public sealed class OAuthConfiguration : OAuthConfigurationBase /// /// The client redirect URL. Not used by all providers. /// - public Uri ServerUrl { get; set; } + public Uri? ServerUrl { get; set; } /// /// The authentication server URL. Not used by all providers. /// - public Uri RedirectUrl { get; set; } + public Uri? RedirectUrl { get; set; } /// /// User information URL override. Not supported by the provider. /// - public Uri UserInformationUrlOverride { get; set; } + public Uri? UserInformationUrlOverride { get; set; } } } From 37267c0cf82f6aa95840fac36719ce971c556b49 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:10:11 -0500 Subject: [PATCH 226/717] Nullify `OAuthConfigurationBase` --- .../Configuration/OAuthConfigurationBase.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/OAuthConfigurationBase.cs b/src/Tgstation.Server.Host/Configuration/OAuthConfigurationBase.cs index ab77c0fcbc2..a170cd235f3 100644 --- a/src/Tgstation.Server.Host/Configuration/OAuthConfigurationBase.cs +++ b/src/Tgstation.Server.Host/Configuration/OAuthConfigurationBase.cs @@ -1,7 +1,5 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.Configuration { /// @@ -12,12 +10,12 @@ public abstract class OAuthConfigurationBase /// /// The client ID. /// - public string ClientId { get; set; } + public string? ClientId { get; set; } /// /// The client secret. /// - public string ClientSecret { get; set; } + public string? ClientSecret { get; set; } /// /// Initializes a new instance of the class. From ce1ff919a927c6c16f36f8e582d25dd784d37975 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:12:15 -0500 Subject: [PATCH 227/717] Nullify `SecurityConfiguration` Fix a `NullReferenceException` --- .../Configuration/SecurityConfiguration.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/SecurityConfiguration.cs b/src/Tgstation.Server.Host/Configuration/SecurityConfiguration.cs index f6df85278c9..35585612c05 100644 --- a/src/Tgstation.Server.Host/Configuration/SecurityConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/SecurityConfiguration.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Api.Models; -#nullable disable - namespace Tgstation.Server.Host.Configuration { /// @@ -62,12 +60,12 @@ public sealed class SecurityConfiguration /// /// A custom token signing key. Overrides . /// - public string CustomTokenSigningKeyBase64 { get; set; } + public string? CustomTokenSigningKeyBase64 { get; set; } /// /// OAuth provider settings. /// - public IDictionary OAuth + public IDictionary? OAuth { get => oAuth; set @@ -75,10 +73,10 @@ public IDictionary OAuth // Workaround for https://github.com/dotnet/runtime/issues/89547 var publicProperties = typeof(OAuthConfiguration) .GetProperties() - .Where(property => property.CanWrite && property.SetMethod.IsPublic) + .Where(property => property.CanWrite && property.SetMethod!.IsPublic) .ToList(); oAuth = value - .Where( + ?.Where( kvp => !publicProperties.All( prop => prop.GetValue(kvp.Value) == prop.PropertyType.GetDefaultValue())) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); @@ -88,6 +86,6 @@ public IDictionary OAuth /// /// Backing field for . /// - IDictionary oAuth; + IDictionary? oAuth; } } From e62f42c228a8f6f85abfbd6282c7e9da4410fedd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:13:15 -0500 Subject: [PATCH 228/717] Nullify `SwarmConfiguration` --- .../Configuration/SwarmConfiguration.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/SwarmConfiguration.cs b/src/Tgstation.Server.Host/Configuration/SwarmConfiguration.cs index 417203bd1b8..12c9cf25a06 100644 --- a/src/Tgstation.Server.Host/Configuration/SwarmConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/SwarmConfiguration.cs @@ -1,9 +1,8 @@ using System; using Tgstation.Server.Api.Models.Internal; -using YamlDotNet.Serialization; -#nullable disable +using YamlDotNet.Serialization; namespace Tgstation.Server.Host.Configuration { @@ -19,7 +18,7 @@ public sealed class SwarmConfiguration : SwarmServer /// [YamlMember(SerializeAs = typeof(string))] - public override Uri Address + public override Uri? Address { get => base.Address; set => base.Address = value; @@ -27,7 +26,7 @@ public override Uri Address /// [YamlMember(SerializeAs = typeof(string))] - public override Uri PublicAddress + public override Uri? PublicAddress { get => base.PublicAddress; set => base.PublicAddress = value; @@ -37,12 +36,12 @@ public override Uri PublicAddress /// The of the swarm controller. If , the current server is considered the controller. /// [YamlMember(SerializeAs = typeof(string))] - public Uri ControllerAddress { get; set; } + public Uri? ControllerAddress { get; set; } /// /// The private key used for swarm communication. /// - public string PrivateKey { get; set; } + public string? PrivateKey { get; set; } /// /// The number of nodes in addition to the controller required to be connected a server swarm before performing an update. From 2251b11db9ea4a72d7d1c5d9c61872482fac93a0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:13:43 -0500 Subject: [PATCH 229/717] Nullify `UpdatesConfiguration` --- .../Configuration/UpdatesConfiguration.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/UpdatesConfiguration.cs b/src/Tgstation.Server.Host/Configuration/UpdatesConfiguration.cs index a8a4b6c932b..af475412eeb 100644 --- a/src/Tgstation.Server.Host/Configuration/UpdatesConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/UpdatesConfiguration.cs @@ -1,7 +1,5 @@ using Tgstation.Server.Common; -#nullable disable - namespace Tgstation.Server.Host.Configuration { /// @@ -37,11 +35,11 @@ public sealed class UpdatesConfiguration /// /// Prefix before the of TGS published in git tags. /// - public string GitTagPrefix { get; set; } = DefaultGitTagPrefix; + public string? GitTagPrefix { get; set; } = DefaultGitTagPrefix; /// /// Asset package containing the new assembly in zip form. /// - public string UpdatePackageAssetName { get; set; } = DefaultUpdatePackageAssetName; + public string? UpdatePackageAssetName { get; set; } = DefaultUpdatePackageAssetName; } } From 6659a7282b842f49898e58ca0ef51e441230505d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:17:52 -0500 Subject: [PATCH 230/717] Nullify `AbstractHttpClientFactory` --- src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs b/src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs index 0bb43edf284..973551e1d47 100644 --- a/src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs +++ b/src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// From 474fc97c6d08c5f3335f77bb7fd75bf146898c58 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:23:27 -0500 Subject: [PATCH 231/717] Nullify `ApiHeadersProvider` --- .../Utils/ApiHeadersProvider.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/ApiHeadersProvider.cs b/src/Tgstation.Server.Host/Utils/ApiHeadersProvider.cs index 95190dc500e..1805d337c1c 100644 --- a/src/Tgstation.Server.Host/Utils/ApiHeadersProvider.cs +++ b/src/Tgstation.Server.Host/Utils/ApiHeadersProvider.cs @@ -4,20 +4,18 @@ using Tgstation.Server.Api; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// sealed class ApiHeadersProvider : IApiHeadersProvider { /// - public ApiHeaders ApiHeaders => attemptedApiHeadersCreation + public ApiHeaders? ApiHeaders => attemptedApiHeadersCreation ? apiHeaders : CreateApiHeaders(false); /// - public HeadersException HeadersException { get; private set; } + public HeadersException? HeadersException { get; private set; } /// /// The for the . @@ -27,7 +25,7 @@ sealed class ApiHeadersProvider : IApiHeadersProvider /// /// Backing field for . /// - ApiHeaders apiHeaders; + ApiHeaders? apiHeaders; /// /// If populating was previously attempted. @@ -44,14 +42,14 @@ public ApiHeadersProvider(IHttpContextAccessor httpContextAccessor) } /// - public ApiHeaders CreateAuthlessHeaders() => CreateApiHeaders(true); + public ApiHeaders CreateAuthlessHeaders() => CreateApiHeaders(true)!; /// /// Attempt to parse from the , optionally populating the properties. /// /// If the error should be ignored and / should not be populated. /// A newly parsed or if was set and the parse failed. - ApiHeaders CreateApiHeaders(bool authless) + ApiHeaders? CreateApiHeaders(bool authless) { if (httpContextAccessor.HttpContext == null) throw new InvalidOperationException("httpContextAccessor has no HttpContext!"); From ad24b5729ea84635ba3bc51ff5bcee32a23e9184 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:26:51 -0500 Subject: [PATCH 232/717] Nullify `AsyncDelayer` --- src/Tgstation.Server.Host/Utils/AsyncDelayer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/AsyncDelayer.cs b/src/Tgstation.Server.Host/Utils/AsyncDelayer.cs index a435e38e9e7..79ffce18386 100644 --- a/src/Tgstation.Server.Host/Utils/AsyncDelayer.cs +++ b/src/Tgstation.Server.Host/Utils/AsyncDelayer.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// From c70d911994ce417a172cb1b9eabddb09b4d37fd5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:28:19 -0500 Subject: [PATCH 233/717] Nullify `FifoSemaphore` --- src/Tgstation.Server.Host/Utils/FifoSemaphore.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/FifoSemaphore.cs b/src/Tgstation.Server.Host/Utils/FifoSemaphore.cs index 099eea7d37c..0bb696680a2 100644 --- a/src/Tgstation.Server.Host/Utils/FifoSemaphore.cs +++ b/src/Tgstation.Server.Host/Utils/FifoSemaphore.cs @@ -3,8 +3,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// @@ -53,7 +51,7 @@ public FifoSemaphore() /// A resulting in the locked . public async ValueTask Lock(CancellationToken cancellationToken) { - FifoSemaphoreTicket ticket = null; + FifoSemaphoreTicket? ticket = null; using (cancellationToken.Register( () => { @@ -65,7 +63,7 @@ public async ValueTask Lock(CancellationToken cancellation var context = await SemaphoreSlimContext.Lock(semaphore, cancellationToken); try { - FifoSemaphoreTicket peekedTicket = null; + FifoSemaphoreTicket? peekedTicket = null; while (ticketQueue.Count > 0) { peekedTicket = ticketQueue.Peek(); From c007c24a91b412917128cfbd268c3e34e68f8994 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:29:03 -0500 Subject: [PATCH 234/717] Nullify `IApiHeadersProvider` --- src/Tgstation.Server.Host/Utils/IApiHeadersProvider.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/IApiHeadersProvider.cs b/src/Tgstation.Server.Host/Utils/IApiHeadersProvider.cs index ea58c98199f..bf3aa714bfc 100644 --- a/src/Tgstation.Server.Host/Utils/IApiHeadersProvider.cs +++ b/src/Tgstation.Server.Host/Utils/IApiHeadersProvider.cs @@ -1,7 +1,5 @@ using Tgstation.Server.Api; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// @@ -12,12 +10,12 @@ public interface IApiHeadersProvider /// /// The created , if any. /// - ApiHeaders ApiHeaders { get; } + ApiHeaders? ApiHeaders { get; } /// /// The thrown when attempting to parse the if any. /// - HeadersException HeadersException { get; } + HeadersException? HeadersException { get; } /// /// Attempt to create without checking for the presence of an header. From a88c55be4970d25a729e51488fcbde871102b3ea Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:29:13 -0500 Subject: [PATCH 235/717] Nullify `IAsyncDelayer` --- src/Tgstation.Server.Host/Utils/IAsyncDelayer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/IAsyncDelayer.cs b/src/Tgstation.Server.Host/Utils/IAsyncDelayer.cs index 38e738f5a2c..d47c5cbc626 100644 --- a/src/Tgstation.Server.Host/Utils/IAsyncDelayer.cs +++ b/src/Tgstation.Server.Host/Utils/IAsyncDelayer.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// From e964606589125849533b4df63e98c13b210bf73f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:29:26 -0500 Subject: [PATCH 236/717] Nullify `IPortAllocator` --- src/Tgstation.Server.Host/Utils/IPortAllocator.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/IPortAllocator.cs b/src/Tgstation.Server.Host/Utils/IPortAllocator.cs index 92a0f480b25..29d234ec62c 100644 --- a/src/Tgstation.Server.Host/Utils/IPortAllocator.cs +++ b/src/Tgstation.Server.Host/Utils/IPortAllocator.cs @@ -1,8 +1,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// From 0ebb0b1ee68e4f42a416f8a753277276cbaac733 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:31:19 -0500 Subject: [PATCH 237/717] Nullify `OpenApiEnumVarNamesExtension` --- .../Utils/OpenApiEnumVarNamesExtension.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/OpenApiEnumVarNamesExtension.cs b/src/Tgstation.Server.Host/Utils/OpenApiEnumVarNamesExtension.cs index 75c71c75616..6953cc6480b 100644 --- a/src/Tgstation.Server.Host/Utils/OpenApiEnumVarNamesExtension.cs +++ b/src/Tgstation.Server.Host/Utils/OpenApiEnumVarNamesExtension.cs @@ -5,8 +5,6 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Writers; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// @@ -51,8 +49,8 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) writer.WriteStartArray(); foreach (var enumValue in Enum.GetValues(enumType)) { - var enumName = enumValue.ToString(); - var field = enumType.GetField(enumName); + var enumName = enumValue.ToString()!; + var field = enumType.GetField(enumName)!; if (field.IsDefined(typeof(ObsoleteAttribute), false)) enumName = $"DEPRECATED_{enumName}"; From 260c89bb09b213bd49f5955da53897cb4f9ada23 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:31:42 -0500 Subject: [PATCH 238/717] Nullify `PortAllocator` --- src/Tgstation.Server.Host/Utils/PortAllocator.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/PortAllocator.cs b/src/Tgstation.Server.Host/Utils/PortAllocator.cs index 546668e8d2e..310cfbfe3da 100644 --- a/src/Tgstation.Server.Host/Utils/PortAllocator.cs +++ b/src/Tgstation.Server.Host/Utils/PortAllocator.cs @@ -14,8 +14,6 @@ using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// From 55acf36edf022691d2ddf4747713a12c0b95dd59 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:34:59 -0500 Subject: [PATCH 239/717] Nullify `ReferenceCounter` --- src/Tgstation.Server.Host/Utils/ReferenceCounter.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/ReferenceCounter.cs b/src/Tgstation.Server.Host/Utils/ReferenceCounter.cs index 19f8408eed3..6377c0295f0 100644 --- a/src/Tgstation.Server.Host/Utils/ReferenceCounter.cs +++ b/src/Tgstation.Server.Host/Utils/ReferenceCounter.cs @@ -1,7 +1,5 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// @@ -24,12 +22,12 @@ abstract class ReferenceCounter : IDisposable /// /// Backing field for . /// - TInstance actualInstance; + TInstance? actualInstance; /// /// The to take when is called. /// - Action referenceCleanupAction; + Action? referenceCleanupAction; /// /// If the was initialized. From bcd875e606e45f74db32005507e35ae927d84a34 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:37:09 -0500 Subject: [PATCH 240/717] Nullify `ReferenceCountingContainer` --- .../Utils/ReferenceCountingContainer.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/ReferenceCountingContainer.cs b/src/Tgstation.Server.Host/Utils/ReferenceCountingContainer.cs index 2389435a6f2..798fc2d16b7 100644 --- a/src/Tgstation.Server.Host/Utils/ReferenceCountingContainer.cs +++ b/src/Tgstation.Server.Host/Utils/ReferenceCountingContainer.cs @@ -1,8 +1,6 @@ using System; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// @@ -30,7 +28,7 @@ public Task OnZeroReferences { if (referenceCount == 0) return Task.CompletedTask; - return onZeroReferencesTcs.Task; + return onZeroReferencesTcs!.Task; } } } @@ -43,7 +41,7 @@ public Task OnZeroReferences /// /// Backing for . /// - TaskCompletionSource onZeroReferencesTcs; + TaskCompletionSource? onZeroReferencesTcs; /// /// Count of active s. @@ -79,7 +77,7 @@ public TReference AddReference() { lock (referenceCountLock) if (--referenceCount == 0) - onZeroReferencesTcs.SetResult(); + onZeroReferencesTcs!.SetResult(); }); return reference; } From b191d0a0c95608b09efb39e87cdddc3ce215c142 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:37:35 -0500 Subject: [PATCH 241/717] Nullify `SemaphoreSlimContext` --- src/Tgstation.Server.Host/Utils/SemaphoreSlimContext.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/SemaphoreSlimContext.cs b/src/Tgstation.Server.Host/Utils/SemaphoreSlimContext.cs index 4339515859a..e9a40d7c68d 100644 --- a/src/Tgstation.Server.Host/Utils/SemaphoreSlimContext.cs +++ b/src/Tgstation.Server.Host/Utils/SemaphoreSlimContext.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// @@ -30,7 +28,7 @@ public static async ValueTask Lock(SemaphoreSlim semaphore /// The to lock. /// The result of the lock attempt. /// A for the lock on success, or if it was not acquired. - public static SemaphoreSlimContext TryLock(SemaphoreSlim semaphore, out bool locked) + public static SemaphoreSlimContext? TryLock(SemaphoreSlim semaphore, out bool locked) { ArgumentNullException.ThrowIfNull(semaphore); locked = semaphore.Wait(TimeSpan.Zero); From 7cd4af72b79204ffe07224a46a5a7238236194f9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:38:41 -0500 Subject: [PATCH 242/717] Nullify `SwaggerConfiguration` --- src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs b/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs index aeaa86db108..a700ccc9cba 100644 --- a/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs +++ b/src/Tgstation.Server.Host/Utils/SwaggerConfiguration.cs @@ -20,8 +20,6 @@ using Tgstation.Server.Host.Controllers; using Tgstation.Server.Host.Security; -#nullable disable - namespace Tgstation.Server.Host.Utils { /// @@ -347,7 +345,7 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) ArgumentNullException.ThrowIfNull(operation); ArgumentNullException.ThrowIfNull(context); - operation.OperationId = $"{context.MethodInfo.DeclaringType.Name}.{context.MethodInfo.Name}"; + operation.OperationId = $"{context.MethodInfo.DeclaringType!.Name}.{context.MethodInfo.Name}"; var authAttributes = context .MethodInfo From 5874475e5991d60c187a47d9f450697196dd4767 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:54:11 -0500 Subject: [PATCH 243/717] Add `.Require` Model extension --- .../Models/ModelExtensions.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/Tgstation.Server.Host/Models/ModelExtensions.cs diff --git a/src/Tgstation.Server.Host/Models/ModelExtensions.cs b/src/Tgstation.Server.Host/Models/ModelExtensions.cs new file mode 100644 index 00000000000..0c88a1ab07f --- /dev/null +++ b/src/Tgstation.Server.Host/Models/ModelExtensions.cs @@ -0,0 +1,40 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; + +using Tgstation.Server.Api.Models; + +namespace Tgstation.Server.Host.Models +{ + /// + /// Extensions for . + /// + static class ModelExtensions + { + /// + /// Require a given property of a given be non-. + /// + /// The of the being accessed. + /// The of the property being accessed. + /// The . + /// The access . + /// The value of in . + /// When in is . + public static TProperty Require(this TModel model, Expression> accessor) + where TModel : EntityId + where TProperty : struct + { + ArgumentNullException.ThrowIfNull(model); + ArgumentNullException.ThrowIfNull(accessor); + + var memberSelectorExpression = (MemberExpression)accessor.Body; + var property = (PropertyInfo)memberSelectorExpression.Member; + + var nullableValue = (TProperty?)property.GetValue(model); + if (!nullableValue.HasValue) + throw new InvalidOperationException($"Expected {model.GetType().Name}.{property.Name} to be set here!"); + + return nullableValue.Value; + } + } +} From 874e012f1b7da66f8b4fe6d4ffcdc416490e0f07 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:54:26 -0500 Subject: [PATCH 244/717] Nullify `ComprehensiveHubContext` --- .../Utils/SignalR/ComprehensiveHubContext.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/SignalR/ComprehensiveHubContext.cs b/src/Tgstation.Server.Host/Utils/SignalR/ComprehensiveHubContext.cs index 27d842c3e11..d9c32143cef 100644 --- a/src/Tgstation.Server.Host/Utils/SignalR/ComprehensiveHubContext.cs +++ b/src/Tgstation.Server.Host/Utils/SignalR/ComprehensiveHubContext.cs @@ -11,8 +11,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; -#nullable disable - namespace Tgstation.Server.Host.Utils.SignalR { /// @@ -46,7 +44,7 @@ sealed class ComprehensiveHubContext : IConnectionMappedHubCo readonly ConcurrentDictionary> userConnections; /// - public event Func, Task>, CancellationToken, ValueTask> OnConnectionMapGroups; + public event Func, Task>, CancellationToken, ValueTask>? OnConnectionMapGroups; /// /// Initializes a new instance of the class. @@ -67,7 +65,7 @@ public ComprehensiveHubContext( public List UserConnectionIds(User user) { ArgumentNullException.ThrowIfNull(user); - var connectionIds = userConnections.GetOrAdd(user.Id.Value, _ => new Dictionary()); + var connectionIds = userConnections.GetOrAdd(user.Require(x => x.Id), _ => new Dictionary()); lock (connectionIds) return connectionIds.Keys.ToList(); } @@ -78,7 +76,7 @@ public ValueTask UserConnected(IAuthenticationContext authenticationContext, THu ArgumentNullException.ThrowIfNull(authenticationContext); ArgumentNullException.ThrowIfNull(hub); - var userId = authenticationContext.User.Id.Value; + var userId = authenticationContext.User.Require(x => x.Id); var context = hub.Context; logger.LogTrace( "Mapping user {userId} to hub connection ID: {connectionId}", @@ -131,11 +129,12 @@ public void UserDisconnected(string connectionId) public void AbortUnauthedConnections(User user) { ArgumentNullException.ThrowIfNull(user); - logger.LogTrace("NotifyAndAbortUnauthedConnections. UID {userId}", user.Id.Value); + var uid = user.Require(x => x.Id); + logger.LogTrace("NotifyAndAbortUnauthedConnections. UID {userId}", uid); - List connections = null; + List? connections = null; userConnections.AddOrUpdate( - user.Id.Value, + uid, _ => new Dictionary(), (_, old) => { @@ -148,7 +147,7 @@ public void AbortUnauthedConnections(User user) return old; }); - foreach (var context in connections) + foreach (var context in connections!) context.Abort(); } } From f1256bc7305af1b1ae9cb37afda1c7485b75f7fc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:55:01 -0500 Subject: [PATCH 245/717] Nullify `ConnectionMappingHub` --- .../Utils/SignalR/ConnectionMappingHub.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/SignalR/ConnectionMappingHub.cs b/src/Tgstation.Server.Host/Utils/SignalR/ConnectionMappingHub.cs index 86849018207..80e89089fa0 100644 --- a/src/Tgstation.Server.Host/Utils/SignalR/ConnectionMappingHub.cs +++ b/src/Tgstation.Server.Host/Utils/SignalR/ConnectionMappingHub.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Host.Security; -#nullable disable - namespace Tgstation.Server.Host.Utils.SignalR { /// @@ -52,7 +50,7 @@ public override async Task OnConnectedAsync() /// [AllowAnonymous] - public override Task OnDisconnectedAsync(Exception exception) + public override Task OnDisconnectedAsync(Exception? exception) { connectionMapper.UserDisconnected(Context.ConnectionId); return base.OnDisconnectedAsync(exception); From fc53e3cf67b1fc264f60af5efa65ea9f32169b16 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:55:24 -0500 Subject: [PATCH 246/717] Nullify `IConnectionMappedHubContext` --- .../Utils/SignalR/IConnectionMappedHubContext.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/SignalR/IConnectionMappedHubContext.cs b/src/Tgstation.Server.Host/Utils/SignalR/IConnectionMappedHubContext.cs index bdf89de2776..101e8e599e6 100644 --- a/src/Tgstation.Server.Host/Utils/SignalR/IConnectionMappedHubContext.cs +++ b/src/Tgstation.Server.Host/Utils/SignalR/IConnectionMappedHubContext.cs @@ -8,8 +8,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; -#nullable disable - namespace Tgstation.Server.Host.Utils.SignalR { /// From e8d45282a8700412029be9333a1a3270a1a43979 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 19:55:41 -0500 Subject: [PATCH 247/717] Nullify `IHubConnectionMapper` --- src/Tgstation.Server.Host/Utils/SignalR/IHubConnectionMapper.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/SignalR/IHubConnectionMapper.cs b/src/Tgstation.Server.Host/Utils/SignalR/IHubConnectionMapper.cs index 8163a737e4c..4521c87fcce 100644 --- a/src/Tgstation.Server.Host/Utils/SignalR/IHubConnectionMapper.cs +++ b/src/Tgstation.Server.Host/Utils/SignalR/IHubConnectionMapper.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; -#nullable disable - namespace Tgstation.Server.Host.Utils.SignalR { /// From 808ccc66433bb4842a7f314ca776bdc731e7d188 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:07:46 -0500 Subject: [PATCH 248/717] Nullify `GitHubClientFactory` --- .../Utils/GitHub/GitHubClientFactory.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs b/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs index 40f76ecb572..e479388b79b 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/GitHubClientFactory.cs @@ -9,8 +9,6 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Utils.GitHub { /// @@ -78,7 +76,7 @@ public IGitHubClient CreateClient(string accessToken) /// /// Optional access token to use as credentials. /// The for the given . - GitHubClient GetOrCreateClient(string accessToken) + GitHubClient GetOrCreateClient(string? accessToken) { GitHubClient client; bool cacheHit; @@ -99,10 +97,11 @@ GitHubClient GetOrCreateClient(string accessToken) var now = DateTimeOffset.UtcNow; if (!cacheHit) { + var product = assemblyInformationProvider.ProductInfoHeaderValue.Product!; client = new GitHubClient( new ProductHeaderValue( - assemblyInformationProvider.ProductInfoHeaderValue.Product.Name, - assemblyInformationProvider.ProductInfoHeaderValue.Product.Version)); + product.Name, + product.Version)); if (accessToken != null) client.Credentials = new Credentials(accessToken); From 0ee812a833887d0acb2f711d68571f92ad3aa766 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:12:25 -0500 Subject: [PATCH 249/717] Nullify `GitHubService` --- .../Utils/GitHub/GitHubService.cs | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs b/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs index 4e95f01820d..a56c956ebf2 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/GitHubService.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Utils.GitHub { /// @@ -82,36 +80,38 @@ public async ValueTask> GetTgsReleases(Cancellation .GetAll(updatesConfiguration.GitHubRepositoryId) .WaitAsync(cancellationToken); + var gitPrefix = updatesConfiguration.GitTagPrefix ?? String.Empty; + logger.LogTrace("{totalReleases} total releases", allReleases.Count); - var releases = allReleases - .Where(release => + var releases = allReleases! + .Where(release => + { + if (!release.PublishedAt.HasValue) { - if (!release.PublishedAt.HasValue) - { - logger.LogDebug("Release tag without PublishedAt: {releaseTag}", release.TagName); - return false; - } - - if (!release.TagName.StartsWith(updatesConfiguration.GitTagPrefix, StringComparison.InvariantCulture)) - return false; - - return true; - }) - .GroupBy(release => + logger.LogDebug("Release tag without PublishedAt: {releaseTag}", release.TagName); + return false; + } + + if (!release.TagName.StartsWith(gitPrefix, StringComparison.InvariantCulture)) + return false; + + return true; + }) + .GroupBy(release => + { + if (!Version.TryParse(release.TagName.Replace(gitPrefix, String.Empty, StringComparison.Ordinal), out var version)) { - if (!Version.TryParse(release.TagName.Replace(updatesConfiguration.GitTagPrefix, String.Empty, StringComparison.Ordinal), out var version)) - { - logger.LogDebug("Unparsable release tag: {releaseTag}", release.TagName); - return null; - } + logger.LogDebug("Unparsable release tag: {releaseTag}", release.TagName); + return null; + } - return version; - }) - .Where(grouping => grouping.Key != null) + return version; + }) + .Where(grouping => grouping.Key != null) - // GitHub can return the same result twice or some other nonsense - .Select(grouping => Tuple.Create(grouping.Key, grouping.OrderBy(x => x.PublishedAt.Value).First())) - .ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2); + // GitHub can return the same result twice or some other nonsense + .Select(grouping => Tuple.Create(grouping.Key!, grouping.OrderBy(x => x.PublishedAt ?? DateTimeOffset.MinValue).First())) + .ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2); logger.LogTrace("{parsedReleases} parsed releases", releases.Count); return releases; From 0bffaea6dbeff246be4804d6b286fc1eccdd951d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:12:47 -0500 Subject: [PATCH 250/717] Nullify `GitHubServiceFactory` --- src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs b/src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs index adb8d32c478..efa08d13bba 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/GitHubServiceFactory.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Utils.GitHub { /// From 707766a934316c119d13feded060a03f434446f7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:13:07 -0500 Subject: [PATCH 251/717] Nullify `IAuthenticatedGitHubService` --- .../Utils/GitHub/IAuthenticatedGitHubService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/GitHub/IAuthenticatedGitHubService.cs b/src/Tgstation.Server.Host/Utils/GitHub/IAuthenticatedGitHubService.cs index 046ef67e773..619bcead205 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/IAuthenticatedGitHubService.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/IAuthenticatedGitHubService.cs @@ -3,8 +3,6 @@ using Octokit; -#nullable disable - namespace Tgstation.Server.Host.Utils.GitHub { /// From d07f5b4cd79be1fbb5456624c99377eae8abad39 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:13:32 -0500 Subject: [PATCH 252/717] Nullify `IGitHubClientFactory` --- src/Tgstation.Server.Host/Utils/GitHub/IGitHubClientFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/GitHub/IGitHubClientFactory.cs b/src/Tgstation.Server.Host/Utils/GitHub/IGitHubClientFactory.cs index 8ffea0fbd2b..ec95fd16ab8 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/IGitHubClientFactory.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/IGitHubClientFactory.cs @@ -1,7 +1,5 @@ using Octokit; -#nullable disable - namespace Tgstation.Server.Host.Utils.GitHub { /// From 090dd825942c44ccd315711f2c6e9435736bee25 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:14:02 -0500 Subject: [PATCH 253/717] Nullify `IGitHubService` --- src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs b/src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs index b7bda78b31b..e2f338d77aa 100644 --- a/src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs +++ b/src/Tgstation.Server.Host/Utils/GitHub/IGitHubService.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Utils.GitHub { /// From a310fd8ec9041096d61b5c8461706574e2611a7b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:16:31 -0500 Subject: [PATCH 254/717] Nullify `FileDownloadProvider` --- src/Tgstation.Server.Host/Transfer/FileDownloadProvider.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Transfer/FileDownloadProvider.cs b/src/Tgstation.Server.Host/Transfer/FileDownloadProvider.cs index eee92cce021..1b0428665a5 100644 --- a/src/Tgstation.Server.Host/Transfer/FileDownloadProvider.cs +++ b/src/Tgstation.Server.Host/Transfer/FileDownloadProvider.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Api.Models; -#nullable disable - namespace Tgstation.Server.Host.Transfer { /// @@ -22,7 +20,7 @@ public sealed class FileDownloadProvider /// /// A to specially provide a returning the of the file download. The caller will own the resulting . /// - public Func> StreamProvider { get; } + public Func>? StreamProvider { get; } /// /// The full path to the file on disk to download. @@ -43,7 +41,7 @@ public sealed class FileDownloadProvider /// The value of . public FileDownloadProvider( Func activationCallback, - Func> streamProvider, + Func>? streamProvider, string filePath, bool shareWrite) { From dffe0d1d0880e901f21d07a0924af1c96b304ebe Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:24:23 -0500 Subject: [PATCH 255/717] Nullify `FileTransferService` --- .../Transfer/FileTransferService.cs | 95 +++++++++++-------- .../Transfer/IFileTransferStreamHandler.cs | 12 +-- 2 files changed, 59 insertions(+), 48 deletions(-) diff --git a/src/Tgstation.Server.Host/Transfer/FileTransferService.cs b/src/Tgstation.Server.Host/Transfer/FileTransferService.cs index cbdc5284800..bb1cafa171a 100644 --- a/src/Tgstation.Server.Host/Transfer/FileTransferService.cs +++ b/src/Tgstation.Server.Host/Transfer/FileTransferService.cs @@ -12,8 +12,6 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Transfer { /// @@ -71,6 +69,11 @@ sealed class FileTransferService : IFileTransferTicketProvider, IFileTransferStr /// Task expireTask; + /// + /// If the is disposed. + /// + bool disposed; + /// /// Initializes a new instance of the class. /// @@ -103,12 +106,13 @@ public async ValueTask DisposeAsync() { Task toAwait; lock (synchronizationLock) - if (expireTask != null) + if (!disposed) { disposeCts.Cancel(); disposeCts.Dispose(); + disposed = true; toAwait = expireTask; - expireTask = null; + expireTask = Task.CompletedTask; } else toAwait = Task.CompletedTask; @@ -120,72 +124,86 @@ public async ValueTask DisposeAsync() public FileTicketResponse CreateDownload(FileDownloadProvider downloadProvider) { ArgumentNullException.ThrowIfNull(downloadProvider); + ObjectDisposedException.ThrowIf(disposed, this); logger.LogDebug("Creating download ticket for path {filePath}", downloadProvider.FilePath); - var ticketResult = CreateTicket(); + var ticket = cryptographySuite.GetSecureString(); lock (downloadTickets) - downloadTickets.Add(ticketResult.FileTicket, downloadProvider); + downloadTickets.Add(ticket, downloadProvider); QueueExpiry(() => { lock (downloadTickets) - if (downloadTickets.Remove(ticketResult.FileTicket)) - logger.LogTrace("Expired download ticket {ticket}...", ticketResult.FileTicket); + if (downloadTickets.Remove(ticket)) + logger.LogTrace("Expired download ticket {ticket}...", ticket); }); - logger.LogTrace("Created download ticket {ticket}", ticketResult.FileTicket); + logger.LogTrace("Created download ticket {ticket}", ticket); - return ticketResult; + return new FileTicketResponse + { + FileTicket = ticket, + }; } /// public IFileUploadTicket CreateUpload(FileUploadStreamKind streamKind) { + ObjectDisposedException.ThrowIf(disposed, this); + logger.LogDebug("Creating upload ticket..."); - var uploadTicket = new FileUploadProvider(CreateTicket(), streamKind); + var ticket = cryptographySuite.GetSecureString(); + var uploadTicket = new FileUploadProvider( + new FileTicketResponse + { + FileTicket = ticket, + }, + streamKind); lock (uploadTickets) - uploadTickets.Add(uploadTicket.Ticket.FileTicket, uploadTicket); + uploadTickets.Add(ticket, uploadTicket); QueueExpiry(() => { lock (uploadTickets) - if (uploadTickets.Remove(uploadTicket.Ticket.FileTicket)) - logger.LogTrace("Expired upload ticket {ticket}...", uploadTicket.Ticket.FileTicket); + if (uploadTickets.Remove(ticket)) + logger.LogTrace("Expired upload ticket {ticket}...", ticket); else return; uploadTicket.Expire(); }); - logger.LogTrace("Created upload ticket {ticket}", uploadTicket.Ticket.FileTicket); + logger.LogTrace("Created upload ticket {ticket}", ticket); return uploadTicket; } /// - public async ValueTask> RetrieveDownloadStream(FileTicketResponse ticket, CancellationToken cancellationToken) + public async ValueTask> RetrieveDownloadStream(FileTicketResponse ticketResponse, CancellationToken cancellationToken) { - ArgumentNullException.ThrowIfNull(ticket); + ArgumentNullException.ThrowIfNull(ticketResponse); + ObjectDisposedException.ThrowIf(disposed, this); - FileDownloadProvider downloadProvider; + var ticket = ticketResponse.FileTicket ?? throw new InvalidOperationException("ticketResponse must have FileTicket!"); + FileDownloadProvider? downloadProvider; lock (downloadTickets) { - if (!downloadTickets.TryGetValue(ticket.FileTicket, out downloadProvider)) + if (!downloadTickets.TryGetValue(ticket, out downloadProvider)) { - logger.LogTrace("Download ticket {ticket} not found!", ticket.FileTicket); - return Tuple.Create(null, null); + logger.LogTrace("Download ticket {ticket} not found!", ticket); + return Tuple.Create(null, null); } - downloadTickets.Remove(ticket.FileTicket); + downloadTickets.Remove(ticket); } var errorCode = downloadProvider.ActivationCallback(); if (errorCode.HasValue) { - logger.LogDebug("Download ticket {ticket} failed activation!", ticket.FileTicket); - return Tuple.Create(null, new ErrorMessageResponse(errorCode.Value)); + logger.LogDebug("Download ticket {ticket} failed activation!", ticket); + return Tuple.Create(null, new ErrorMessageResponse(errorCode.Value)); } Stream stream; @@ -198,7 +216,7 @@ public async ValueTask> RetrieveDownloadStre } catch (IOException ex) { - return Tuple.Create( + return Tuple.Create( null, new ErrorMessageResponse(ErrorCode.IOError) { @@ -208,8 +226,8 @@ public async ValueTask> RetrieveDownloadStre try { - logger.LogTrace("Ticket {ticket} downloading...", ticket.FileTicket); - return Tuple.Create(stream, null); + logger.LogTrace("Ticket {ticket} downloading...", ticket); + return Tuple.Create(stream, null); } catch { @@ -219,34 +237,27 @@ public async ValueTask> RetrieveDownloadStre } /// - public async ValueTask SetUploadStream(FileTicketResponse ticket, Stream stream, CancellationToken cancellationToken) + public async ValueTask SetUploadStream(FileTicketResponse ticketResponse, Stream stream, CancellationToken cancellationToken) { - ArgumentNullException.ThrowIfNull(ticket); + ArgumentNullException.ThrowIfNull(ticketResponse); + ObjectDisposedException.ThrowIf(disposed, this); - FileUploadProvider uploadProvider; + var ticket = ticketResponse.FileTicket ?? throw new InvalidOperationException("ticketResponse must have FileTicket!"); + FileUploadProvider? uploadProvider; lock (uploadTickets) { - if (!uploadTickets.TryGetValue(ticket.FileTicket, out uploadProvider)) + if (!uploadTickets.TryGetValue(ticket, out uploadProvider)) { - logger.LogTrace("Upload ticket {ticket} not found!", ticket.FileTicket); + logger.LogTrace("Upload ticket {ticket} not found!", ticket); return new ErrorMessageResponse(ErrorCode.ResourceNotPresent); } - uploadTickets.Remove(ticket.FileTicket); + uploadTickets.Remove(ticket); } return await uploadProvider.Completion(stream, cancellationToken); } - /// - /// Creates a new . - /// - /// A new . - FileTicketResponse CreateTicket() => new() - { - FileTicket = cryptographySuite.GetSecureString(), - }; - /// /// Queue an to run after . /// diff --git a/src/Tgstation.Server.Host/Transfer/IFileTransferStreamHandler.cs b/src/Tgstation.Server.Host/Transfer/IFileTransferStreamHandler.cs index f0ba7a396da..43ec0275342 100644 --- a/src/Tgstation.Server.Host/Transfer/IFileTransferStreamHandler.cs +++ b/src/Tgstation.Server.Host/Transfer/IFileTransferStreamHandler.cs @@ -15,20 +15,20 @@ namespace Tgstation.Server.Host.Transfer public interface IFileTransferStreamHandler { /// - /// Sets the for a given associated with a pending upload. + /// Sets the for a given associated with a pending upload. /// - /// The . + /// The . /// The with uploaded data. /// The for the operation. /// A resulting in if the upload completed successfully, otherwise. - ValueTask SetUploadStream(FileTicketResponse ticket, Stream stream, CancellationToken cancellationToken); + ValueTask SetUploadStream(FileTicketResponse ticketResponse, Stream stream, CancellationToken cancellationToken); /// - /// Gets the the for a given associated with a pending download. + /// Gets the the for a given associated with a pending download. /// - /// The . + /// The . /// The for the operation. /// A resulting in a containing either a containing the data to download or an to return. - ValueTask> RetrieveDownloadStream(FileTicketResponse ticket, CancellationToken cancellationToken); + ValueTask> RetrieveDownloadStream(FileTicketResponse ticketResponse, CancellationToken cancellationToken); } } From 774315d3fd149e9b511892c8ec27a6eba330e194 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:26:43 -0500 Subject: [PATCH 256/717] Nullify `FileUploadProvider` --- .../Transfer/FileUploadProvider.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs b/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs index 31a691b36ad..db7965f545a 100644 --- a/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs +++ b/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs @@ -9,8 +9,6 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Transfer { /// @@ -27,7 +25,7 @@ sealed class FileUploadProvider : IFileUploadTicket /// /// The for the . /// - readonly TaskCompletionSource streamTcs; + readonly TaskCompletionSource streamTcs; /// /// The that completes in or when is called. @@ -42,7 +40,7 @@ sealed class FileUploadProvider : IFileUploadTicket /// /// The that occurred while processing the upload if any. /// - ErrorMessageResponse errorMessage; + ErrorMessageResponse? errorMessage; /// /// Initializes a new instance of the class. @@ -54,7 +52,7 @@ public FileUploadProvider(FileTicketResponse ticket, FileUploadStreamKind stream Ticket = ticket ?? throw new ArgumentNullException(nameof(ticket)); ticketExpiryCts = new CancellationTokenSource(); - streamTcs = new TaskCompletionSource(); + streamTcs = new TaskCompletionSource(); completionTcs = new TaskCompletionSource(); this.streamKind = streamKind; } @@ -68,7 +66,7 @@ public ValueTask DisposeAsync() } /// - public async ValueTask GetResult(CancellationToken cancellationToken) + public async ValueTask GetResult(CancellationToken cancellationToken) { using (cancellationToken.Register(() => streamTcs.TrySetCanceled(cancellationToken))) using (ticketExpiryCts.Token.Register(() => streamTcs.TrySetResult(null))) @@ -90,14 +88,14 @@ public void Expire() /// The containing uploaded data. /// The for the operation. /// A resulting in , otherwise. - public async ValueTask Completion(Stream stream, CancellationToken cancellationToken) + public async ValueTask Completion(Stream stream, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(stream); if (ticketExpiryCts.IsCancellationRequested) return new ErrorMessageResponse(ErrorCode.ResourceNotPresent); - Stream bufferedStream = null; + Stream? bufferedStream = null; try { switch (streamKind) From 5441e17880b30113cf403064cbdc363fe8967a45 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:27:16 -0500 Subject: [PATCH 257/717] Nullify `IFileTransferStreamHandler` --- .../Transfer/IFileTransferStreamHandler.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Transfer/IFileTransferStreamHandler.cs b/src/Tgstation.Server.Host/Transfer/IFileTransferStreamHandler.cs index 43ec0275342..45aafc7cd7c 100644 --- a/src/Tgstation.Server.Host/Transfer/IFileTransferStreamHandler.cs +++ b/src/Tgstation.Server.Host/Transfer/IFileTransferStreamHandler.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Transfer { /// @@ -21,7 +19,7 @@ public interface IFileTransferStreamHandler /// The with uploaded data. /// The for the operation. /// A resulting in if the upload completed successfully, otherwise. - ValueTask SetUploadStream(FileTicketResponse ticketResponse, Stream stream, CancellationToken cancellationToken); + ValueTask SetUploadStream(FileTicketResponse ticketResponse, Stream stream, CancellationToken cancellationToken); /// /// Gets the the for a given associated with a pending download. @@ -29,6 +27,6 @@ public interface IFileTransferStreamHandler /// The . /// The for the operation. /// A resulting in a containing either a containing the data to download or an to return. - ValueTask> RetrieveDownloadStream(FileTicketResponse ticketResponse, CancellationToken cancellationToken); + ValueTask> RetrieveDownloadStream(FileTicketResponse ticketResponse, CancellationToken cancellationToken); } } From a551699729352a73f7b8ab5fcdec08ee1c17aee4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:27:32 -0500 Subject: [PATCH 258/717] Nullify `IFileTransferTicketProvider` --- .../Transfer/IFileTransferTicketProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Transfer/IFileTransferTicketProvider.cs b/src/Tgstation.Server.Host/Transfer/IFileTransferTicketProvider.cs index 98a2bfd9131..1a13cb9f87d 100644 --- a/src/Tgstation.Server.Host/Transfer/IFileTransferTicketProvider.cs +++ b/src/Tgstation.Server.Host/Transfer/IFileTransferTicketProvider.cs @@ -1,7 +1,5 @@ using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Transfer { /// From ba7ce116ec563a1c1ab62e20c32aaedec551cc81 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:28:05 -0500 Subject: [PATCH 259/717] Nullify `IFileUploadTicket` --- src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs | 2 +- src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs b/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs index db7965f545a..23b37788fc6 100644 --- a/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs +++ b/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs @@ -131,7 +131,7 @@ public void Expire() } /// - public void SetError(ErrorCode errorCode, string additionalData) + public void SetError(ErrorCode errorCode, string? additionalData) { if (errorMessage != null) throw new InvalidOperationException("Error already set!"); diff --git a/src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs b/src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs index 260be9573fb..43130810d37 100644 --- a/src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs +++ b/src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Transfer { /// @@ -21,6 +19,6 @@ public interface IFileUploadTicket : IFileStreamProvider /// /// The to set. /// Any additional information that can be provided about the error. - void SetError(ErrorCode errorCode, string additionalData); + void SetError(ErrorCode errorCode, string? additionalData); } } From a61c0711f09fc20aaaa4811c3abbe80a27d401a4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:28:27 -0500 Subject: [PATCH 260/717] Nullify `AssemblyInformationProvider` --- .../System/AssemblyInformationProvider.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs b/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs index 4d072772e5d..475eb498626 100644 --- a/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs +++ b/src/Tgstation.Server.Host/System/AssemblyInformationProvider.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Common; using Tgstation.Server.Common.Extensions; -#nullable disable - namespace Tgstation.Server.Host.System { /// @@ -40,7 +38,7 @@ public AssemblyInformationProvider() Assembly assembly = Assembly.GetExecutingAssembly(); Path = assembly.Location; AssemblyName = assembly.GetName(); - Version = AssemblyName.Version.Semver(); + Version = AssemblyName.Version!.Semver(); VersionString = String.Concat(VersionPrefix, "-v", Version); } } From 42a13bbe8f9664d2ef3999c71ac8414181e73cb2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:28:42 -0500 Subject: [PATCH 261/717] Nullify `IAssemblyInformationProvider` --- .../System/IAssemblyInformationProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/System/IAssemblyInformationProvider.cs b/src/Tgstation.Server.Host/System/IAssemblyInformationProvider.cs index 7b092f8aeaa..184dd9f60a1 100644 --- a/src/Tgstation.Server.Host/System/IAssemblyInformationProvider.cs +++ b/src/Tgstation.Server.Host/System/IAssemblyInformationProvider.cs @@ -2,8 +2,6 @@ using System.Net.Http.Headers; using System.Reflection; -#nullable disable - namespace Tgstation.Server.Host.System { /// From 4b1d9d0ee1fc25a2bad5efc4e2081f045fee2de4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:29:01 -0500 Subject: [PATCH 262/717] Nullify `IPlatformIdentifier` --- src/Tgstation.Server.Host/System/IPlatformIdentifier.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/System/IPlatformIdentifier.cs b/src/Tgstation.Server.Host/System/IPlatformIdentifier.cs index 104bb0dc329..805b93b97d4 100644 --- a/src/Tgstation.Server.Host/System/IPlatformIdentifier.cs +++ b/src/Tgstation.Server.Host/System/IPlatformIdentifier.cs @@ -1,7 +1,5 @@ using System.Runtime.Versioning; -#nullable disable - namespace Tgstation.Server.Host.System { /// From 47cf9519033c57062dd89f3f51bf54b7b5bbe2e2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:29:36 -0500 Subject: [PATCH 263/717] Nullify `IPlatformIdentifier` --- src/Tgstation.Server.Host/System/IProcess.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/System/IProcess.cs b/src/Tgstation.Server.Host/System/IProcess.cs index 7b033f3e9d0..8df102b2b2a 100644 --- a/src/Tgstation.Server.Host/System/IProcess.cs +++ b/src/Tgstation.Server.Host/System/IProcess.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.System { /// From 643b6404fd500fd182d51a9d3345b8a2adb23081 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:29:56 -0500 Subject: [PATCH 264/717] Nullify `IProcessBase` --- src/Tgstation.Server.Host/System/IProcessBase.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/System/IProcessBase.cs b/src/Tgstation.Server.Host/System/IProcessBase.cs index 91feee546eb..8fc0bd4484e 100644 --- a/src/Tgstation.Server.Host/System/IProcessBase.cs +++ b/src/Tgstation.Server.Host/System/IProcessBase.cs @@ -1,8 +1,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.System { /// From 22d97588fa1448f09e394a3271ced359be65739d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:30:23 -0500 Subject: [PATCH 265/717] Nullify `IProcessExecutor` --- src/Tgstation.Server.Host/System/IProcessExecutor.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/System/IProcessExecutor.cs b/src/Tgstation.Server.Host/System/IProcessExecutor.cs index a0418aea0df..fe51ce451b1 100644 --- a/src/Tgstation.Server.Host/System/IProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/IProcessExecutor.cs @@ -1,6 +1,4 @@ -#nullable disable - -namespace Tgstation.Server.Host.System +namespace Tgstation.Server.Host.System { /// /// For launching '. @@ -20,8 +18,8 @@ interface IProcessExecutor IProcess LaunchProcess( string fileName, string workingDirectory, - string arguments = null, - string fileRedirect = null, + string? arguments = null, + string? fileRedirect = null, bool readStandardHandles = false, bool noShellExecute = false); From b689d9d4c03bd4fb430b2382c7bacfe8ac231335 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:30:41 -0500 Subject: [PATCH 266/717] Nullify `IProcessFeatures` --- src/Tgstation.Server.Host/System/IProcessFeatures.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/System/IProcessFeatures.cs b/src/Tgstation.Server.Host/System/IProcessFeatures.cs index 8d4a9258c60..abfaca6b7bf 100644 --- a/src/Tgstation.Server.Host/System/IProcessFeatures.cs +++ b/src/Tgstation.Server.Host/System/IProcessFeatures.cs @@ -1,8 +1,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.System { /// From acaa178cb11669a7897bb6e1a35eb96a41e8422c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:31:01 -0500 Subject: [PATCH 267/717] Nullify `NativeMethods` --- src/Tgstation.Server.Host/System/NativeMethods.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/System/NativeMethods.cs b/src/Tgstation.Server.Host/System/NativeMethods.cs index 11f465fb139..dc5046d1335 100644 --- a/src/Tgstation.Server.Host/System/NativeMethods.cs +++ b/src/Tgstation.Server.Host/System/NativeMethods.cs @@ -2,8 +2,6 @@ using System.Runtime.InteropServices; using System.Text; -#nullable disable - namespace Tgstation.Server.Host.System { /// From 40f5b743036c11fb9a0b28343aa5a19d8257f6c9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:31:15 -0500 Subject: [PATCH 268/717] Nullify `PlatformIdentifier` --- src/Tgstation.Server.Host/System/PlatformIdentifier.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/System/PlatformIdentifier.cs b/src/Tgstation.Server.Host/System/PlatformIdentifier.cs index 6391932f1c9..22931b97ce1 100644 --- a/src/Tgstation.Server.Host/System/PlatformIdentifier.cs +++ b/src/Tgstation.Server.Host/System/PlatformIdentifier.cs @@ -1,8 +1,6 @@ using System.Runtime.InteropServices; using System.Runtime.Versioning; -#nullable disable - namespace Tgstation.Server.Host.System { /// From f647bb68b6f58f9bf07e56a9a2f38461258f4322 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:31:47 -0500 Subject: [PATCH 269/717] Nullify `PosixProcessFeatures` --- src/Tgstation.Server.Host/System/PosixProcessFeatures.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs b/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs index c1999c4545b..b45c845fa4b 100644 --- a/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs +++ b/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; -#nullable disable - namespace Tgstation.Server.Host.System { /// From 0c7c97c8a5278f2a28563e4981a3785f3a3f1d27 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:32:09 -0500 Subject: [PATCH 270/717] Nullify `PosixSignalHandler` --- src/Tgstation.Server.Host/System/PosixSignalHandler.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/System/PosixSignalHandler.cs b/src/Tgstation.Server.Host/System/PosixSignalHandler.cs index 5342f68d393..eff4f6c7c20 100644 --- a/src/Tgstation.Server.Host/System/PosixSignalHandler.cs +++ b/src/Tgstation.Server.Host/System/PosixSignalHandler.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.System { /// @@ -47,7 +45,7 @@ sealed class PosixSignalHandler : IHostedService, IDisposable /// /// The thread used to check the signal. See http://docs.go-mono.com/?link=T%3aMono.Unix.UnixSignal. /// - Task signalCheckerTask; + Task? signalCheckerTask; /// /// Initializes a new instance of the class. From 4144ed6c99b560ba2b1f9a2fd82e4def431f877c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:33:37 -0500 Subject: [PATCH 271/717] Nullify `Process` --- src/Tgstation.Server.Host/System/Process.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/System/Process.cs b/src/Tgstation.Server.Host/System/Process.cs index a505cee8781..003f3b12e4a 100644 --- a/src/Tgstation.Server.Host/System/Process.cs +++ b/src/Tgstation.Server.Host/System/Process.cs @@ -9,8 +9,6 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.System { /// From 07ad701f57ead8349044796f45e2fe387d69984f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:37:42 -0500 Subject: [PATCH 272/717] Nullify `ProcessExecutor` --- src/Tgstation.Server.Host/System/IProcess.cs | 2 +- .../System/IProcessExecutor.cs | 6 ++-- .../System/PosixProcessFeatures.cs | 2 +- src/Tgstation.Server.Host/System/Process.cs | 8 ++--- .../System/ProcessExecutor.cs | 32 +++++++++---------- 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/Tgstation.Server.Host/System/IProcess.cs b/src/Tgstation.Server.Host/System/IProcess.cs index 8df102b2b2a..f9f35e5c662 100644 --- a/src/Tgstation.Server.Host/System/IProcess.cs +++ b/src/Tgstation.Server.Host/System/IProcess.cs @@ -29,7 +29,7 @@ interface IProcess : IProcessBase, IAsyncDisposable /// the result of this function must be ed before is called. /// May call internally if the process has exited. /// - ValueTask GetCombinedOutput(CancellationToken cancellationToken); + ValueTask GetCombinedOutput(CancellationToken cancellationToken); /// /// Asycnhronously terminates the process. diff --git a/src/Tgstation.Server.Host/System/IProcessExecutor.cs b/src/Tgstation.Server.Host/System/IProcessExecutor.cs index fe51ce451b1..aae807eec25 100644 --- a/src/Tgstation.Server.Host/System/IProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/IProcessExecutor.cs @@ -18,7 +18,7 @@ interface IProcessExecutor IProcess LaunchProcess( string fileName, string workingDirectory, - string? arguments = null, + string arguments, string? fileRedirect = null, bool readStandardHandles = false, bool noShellExecute = false); @@ -34,13 +34,13 @@ IProcess LaunchProcess( /// /// The . /// The represented by on success, on failure. - IProcess GetProcess(int id); + IProcess? GetProcess(int id); /// /// Get a with a given . /// /// The name of the process executable without the extension. /// The represented by on success, on failure. - IProcess GetProcessByName(string name); + IProcess? GetProcessByName(string name); } } diff --git a/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs b/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs index b45c845fa4b..8077577aafa 100644 --- a/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs +++ b/src/Tgstation.Server.Host/System/PosixProcessFeatures.cs @@ -86,7 +86,7 @@ public async ValueTask CreateDump(global::System.Diagnostics.Process process, st throw new JobException(ErrorCode.GameServerOffline, ex); } - string output; + string? output; int exitCode; await using (var gcoreProc = lazyLoadedProcessExecutor.Value.LaunchProcess( GCorePath, diff --git a/src/Tgstation.Server.Host/System/Process.cs b/src/Tgstation.Server.Host/System/Process.cs index 003f3b12e4a..4b91aef6ac4 100644 --- a/src/Tgstation.Server.Host/System/Process.cs +++ b/src/Tgstation.Server.Host/System/Process.cs @@ -57,7 +57,7 @@ sealed class Process : IProcess /// /// The resulting in the process' standard output/error text. /// - readonly Task readTask; + readonly Task? readTask; /// /// If the was disposed. @@ -78,8 +78,8 @@ public Process( IProcessFeatures processFeatures, IAsyncDelayer asyncDelayer, global::System.Diagnostics.Process handle, - CancellationTokenSource readerCts, - Task readTask, + CancellationTokenSource? readerCts, + Task? readTask, ILogger logger, bool preExisting) { @@ -144,7 +144,7 @@ public async ValueTask DisposeAsync() } /// - public async ValueTask GetCombinedOutput(CancellationToken cancellationToken) + public async ValueTask GetCombinedOutput(CancellationToken cancellationToken) { if (readTask == null) throw new InvalidOperationException("Output/Error stream reading was not enabled!"); diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index 94e4af31b7b..fd411153f05 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -9,8 +9,6 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.System { /// @@ -86,7 +84,7 @@ public ProcessExecutor( } /// - public IProcess GetProcess(int id) + public IProcess? GetProcess(int id) { logger.LogDebug("Attaching to process {pid}...", id); global::System.Diagnostics.Process handle; @@ -116,7 +114,7 @@ public IProcess LaunchProcess( string fileName, string workingDirectory, string arguments, - string fileRedirect, + string? fileRedirect, bool readStandardHandles, bool noShellExecute) { @@ -143,11 +141,11 @@ public IProcess LaunchProcess( handle.StartInfo.UseShellExecute = !noShellExecute; - Task readTask = null; - CancellationTokenSource disposeCts = null; + Task? readTask = null; + CancellationTokenSource? disposeCts = null; try { - TaskCompletionSource processStartTcs = null; + TaskCompletionSource? processStartTcs = null; if (readStandardHandles) { processStartTcs = new TaskCompletionSource(); @@ -203,11 +201,11 @@ public IProcess LaunchProcess( } /// - public IProcess GetProcessByName(string name) + public IProcess? GetProcessByName(string name) { logger.LogTrace("GetProcessByName: {processName}...", name ?? throw new ArgumentNullException(nameof(name))); var procs = global::System.Diagnostics.Process.GetProcessesByName(name); - global::System.Diagnostics.Process handle = null; + global::System.Diagnostics.Process? handle = null; foreach (var proc in procs) if (handle == null) handle = proc; @@ -231,7 +229,7 @@ public IProcess GetProcessByName(string name) /// The optional path to redirect the streams to. /// The that triggers when the is disposed. /// A resulting in the program's output/error text if is , otherwise. - async Task ConsumeReaders(global::System.Diagnostics.Process handle, Task startTask, string fileRedirect, CancellationToken disposeToken) + async Task ConsumeReaders(global::System.Diagnostics.Process handle, Task startTask, string? fileRedirect, CancellationToken disposeToken) { await startTask; @@ -241,9 +239,9 @@ async Task ConsumeReaders(global::System.Diagnostics.Process handle, Tas // once we obtain these handles we're responsible for them using var stdOutHandle = handle.StandardOutput; using var stdErrHandle = handle.StandardError; - Task outputReadTask = null, errorReadTask = null; + Task? outputReadTask = null, errorReadTask = null; bool outputOpen = true, errorOpen = true; - async Task GetNextLine() + async Task GetNextLine() { if (outputOpen && outputReadTask == null) outputReadTask = stdOutHandle.ReadLineAsync(disposeToken).AsTask(); @@ -251,7 +249,7 @@ async Task GetNextLine() if (errorOpen && errorReadTask == null) errorReadTask = stdErrHandle.ReadLineAsync(disposeToken).AsTask(); - var completedTask = await Task.WhenAny(outputReadTask ?? errorReadTask, errorReadTask ?? outputReadTask); + var completedTask = await Task.WhenAny(outputReadTask ?? errorReadTask!, errorReadTask ?? outputReadTask!); var line = await completedTask; if (completedTask == outputReadTask) { @@ -275,7 +273,7 @@ async Task GetNextLine() await using var fileStream = fileRedirect != null ? ioManager.CreateAsyncSequentialWriteStream(fileRedirect) : null; await using var writer = fileStream != null ? new StreamWriter(fileStream) : null; - string text; + string? text; var stringBuilder = fileStream == null ? new StringBuilder() : null; try { @@ -283,11 +281,11 @@ async Task GetNextLine() { if (fileStream != null) { - await writer.WriteLineAsync(text.AsMemory(), disposeToken); + await writer!.WriteLineAsync(text.AsMemory(), disposeToken); await writer.FlushAsync(disposeToken); } else - stringBuilder.AppendLine(text); + stringBuilder!.AppendLine(text); } logger.LogTrace("Finished read for PID {pid}", pid); @@ -296,7 +294,7 @@ async Task GetNextLine() { logger.LogWarning(ex, "PID {pid} stream reading interrupted!", pid); if (fileStream != null) - await writer.WriteLineAsync("-- Process detached, log truncated. This is likely due a to TGS restart --"); + await writer!.WriteLineAsync("-- Process detached, log truncated. This is likely due a to TGS restart --"); } return stringBuilder?.ToString(); From 52d8d04f5a31198be7b23c1dc2f5a3bc5add63d6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:43:08 -0500 Subject: [PATCH 273/717] Nullify `ProgramShutdownTokenSource` --- .../System/ProgramShutdownTokenSource.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/System/ProgramShutdownTokenSource.cs b/src/Tgstation.Server.Host/System/ProgramShutdownTokenSource.cs index 0f0dfb13b10..0b9a77f7a6c 100644 --- a/src/Tgstation.Server.Host/System/ProgramShutdownTokenSource.cs +++ b/src/Tgstation.Server.Host/System/ProgramShutdownTokenSource.cs @@ -1,8 +1,6 @@ using System; using System.Threading; -#nullable disable - namespace Tgstation.Server.Host.System { /// @@ -18,7 +16,7 @@ sealed class ProgramShutdownTokenSource : IDisposable /// /// The for the . /// - CancellationTokenSource cancellationTokenSource; + CancellationTokenSource? cancellationTokenSource; /// /// Gets the . From a01173ebc73716845b8171df126aa315aeec8c60 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:52:01 -0500 Subject: [PATCH 274/717] Nullify `SystemDManager` --- src/Tgstation.Server.Host/System/SystemDManager.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/System/SystemDManager.cs b/src/Tgstation.Server.Host/System/SystemDManager.cs index 4e3b86972c7..7b0542fcad1 100644 --- a/src/Tgstation.Server.Host/System/SystemDManager.cs +++ b/src/Tgstation.Server.Host/System/SystemDManager.cs @@ -11,8 +11,6 @@ using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Core; -#nullable disable - namespace Tgstation.Server.Host.System { /// @@ -88,7 +86,7 @@ public override void Dispose() } /// - public ValueTask HandleRestart(Version updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken) + public ValueTask HandleRestart(Version? updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken) { // If this is set, we know a gracefule SHUTDOWN was requested restartInProgress = !handlerMayDelayShutdownWithExtremelyLongRunningTasks; From 5f066f880eeb9ba339ef364568e2232d9b450c40 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:52:24 -0500 Subject: [PATCH 275/717] Nullify `WindowsFirewallHelper` --- src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs b/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs index 7a5e82742f4..74964a5569f 100644 --- a/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs +++ b/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs @@ -4,8 +4,6 @@ using Microsoft.Extensions.Logging; -#nullable disable - namespace Tgstation.Server.Host.System { /// From 30a85d689c4b279c58563d23edd17be016e75c11 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:53:02 -0500 Subject: [PATCH 276/717] Nullify `WindowsNetworkPromptReaper` --- src/Tgstation.Server.Host/System/NativeMethods.cs | 2 +- src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/System/NativeMethods.cs b/src/Tgstation.Server.Host/System/NativeMethods.cs index dc5046d1335..234ba0661a4 100644 --- a/src/Tgstation.Server.Host/System/NativeMethods.cs +++ b/src/Tgstation.Server.Host/System/NativeMethods.cs @@ -54,7 +54,7 @@ public enum MiniDumpType : uint /// See https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-findwindoww. /// [DllImport("user32.dll", CharSet = CharSet.Unicode)] - public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + public static extern IntPtr FindWindow(string? lpClassName, string lpWindowName); /// /// See https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-sendmessage. diff --git a/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs b/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs index c30bbb0359b..48924155719 100644 --- a/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs +++ b/src/Tgstation.Server.Host/System/WindowsNetworkPromptReaper.cs @@ -13,8 +13,6 @@ using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.System { /// From b28cc1a494dad12ac4e0ddc3cb46ab0dabe545cf Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:54:16 -0500 Subject: [PATCH 277/717] Nullify `WindowsProcessFeatures` --- src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs b/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs index c3a3b31d9b7..41789aec8cc 100644 --- a/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs +++ b/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs @@ -14,8 +14,6 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; -#nullable disable - namespace Tgstation.Server.Host.System { /// From 378ce32f9728936a121d5030f2c753916a8925cf Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:55:25 -0500 Subject: [PATCH 278/717] Nullify `IJobManager` --- src/Tgstation.Server.Host/Jobs/IJobManager.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Jobs/IJobManager.cs b/src/Tgstation.Server.Host/Jobs/IJobManager.cs index e8d0a83bafb..58ad8eacd6d 100644 --- a/src/Tgstation.Server.Host/Jobs/IJobManager.cs +++ b/src/Tgstation.Server.Host/Jobs/IJobManager.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Jobs { /// @@ -36,7 +34,7 @@ public interface IJobManager /// A that will cancel the . /// The for the operation. /// A representing the . Results in if the completed without errors, if errors occurred, or if the job isn't registered. - ValueTask WaitForJobCompletion(Job job, User canceller, CancellationToken jobCancellationToken, CancellationToken cancellationToken); + ValueTask WaitForJobCompletion(Job job, User? canceller, CancellationToken jobCancellationToken, CancellationToken cancellationToken); /// /// Cancels a give . @@ -46,6 +44,6 @@ public interface IJobManager /// If the operation should wait until the job exits before completing. /// The for the operation. /// A resulting in the updated if it was cancelled, if it couldn't be found. - ValueTask CancelJob(Job job, User user, bool blocking, CancellationToken cancellationToken); + ValueTask CancelJob(Job job, User? user, bool blocking, CancellationToken cancellationToken); } } From 83c4ddccef8128ec407fd4dccf29d8e3616e22cd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:55:37 -0500 Subject: [PATCH 279/717] Nullify `IJobService` --- src/Tgstation.Server.Host/Jobs/IJobService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Jobs/IJobService.cs b/src/Tgstation.Server.Host/Jobs/IJobService.cs index 847adff98ca..e92ead5e6a6 100644 --- a/src/Tgstation.Server.Host/Jobs/IJobService.cs +++ b/src/Tgstation.Server.Host/Jobs/IJobService.cs @@ -1,7 +1,5 @@ using Tgstation.Server.Host.Components; -#nullable disable - namespace Tgstation.Server.Host.Jobs { /// From 00886fd2ae65d3ef45656247b636d94c2f2c8acc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:55:58 -0500 Subject: [PATCH 280/717] Nullify `JobEntrypoint` --- src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs b/src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs index 1a272153069..79e71b5048c 100644 --- a/src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs +++ b/src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Jobs { /// From e570b733bf871bfff180339d58a8dad098577f80 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:56:23 -0500 Subject: [PATCH 281/717] Nullify `JobException` --- src/Tgstation.Server.Host/Jobs/JobException.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Jobs/JobException.cs b/src/Tgstation.Server.Host/Jobs/JobException.cs index d29697252fe..0eb62f2e29e 100644 --- a/src/Tgstation.Server.Host/Jobs/JobException.cs +++ b/src/Tgstation.Server.Host/Jobs/JobException.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Api.Models; -#nullable disable - namespace Tgstation.Server.Host.Jobs { /// From ae2932bba2d47ba62efcbb287422fbeed6503a67 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:57:02 -0500 Subject: [PATCH 282/717] Nullify `JobHandler` --- src/Tgstation.Server.Host/Jobs/JobHandler.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Jobs/JobHandler.cs b/src/Tgstation.Server.Host/Jobs/JobHandler.cs index 3a290d48ce7..04c3b845101 100644 --- a/src/Tgstation.Server.Host/Jobs/JobHandler.cs +++ b/src/Tgstation.Server.Host/Jobs/JobHandler.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Jobs { /// @@ -24,7 +22,7 @@ sealed class JobHandler : IDisposable /// /// The stage of the job. /// - public string Stage { get; set; } + public string? Stage { get; set; } /// /// The for . @@ -39,7 +37,7 @@ sealed class JobHandler : IDisposable /// /// The being run. /// - Task task; + Task? task; /// /// Initializes a new instance of the class. From da0da4e6ebfbd8202ae05a380c877fb22e527470 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 20:58:16 -0500 Subject: [PATCH 283/717] Nullify `JobProgressReporter` --- .../Jobs/JobProgressReporter.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Jobs/JobProgressReporter.cs b/src/Tgstation.Server.Host/Jobs/JobProgressReporter.cs index 37b7ae03e20..753f8cf519e 100644 --- a/src/Tgstation.Server.Host/Jobs/JobProgressReporter.cs +++ b/src/Tgstation.Server.Host/Jobs/JobProgressReporter.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Jobs { /// @@ -16,7 +14,7 @@ public sealed class JobProgressReporter /// /// The name of the current stage. /// - public string StageName + public string? StageName { get => stageName; set @@ -37,12 +35,12 @@ public string StageName /// /// Progress reporter callback taking a description of what the job is currently doing and the (optional) progress of the job on a scale from 0.0-1.0. /// - readonly Action callback; + readonly Action callback; /// /// Backing field for . /// - string stageName; + string? stageName; /// /// The last progress value pushed into the . @@ -60,7 +58,7 @@ public string StageName /// The value of . /// The value of . /// The value of . - public JobProgressReporter(ILogger logger, string stageName, Action callback) + public JobProgressReporter(ILogger logger, string? stageName, Action callback) { this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.callback = callback ?? throw new ArgumentNullException(nameof(callback)); @@ -99,7 +97,7 @@ public void ReportProgress(double? progress) /// The 0.0f-1.0f percentage of the current 's percentage should be given to the section. /// A new that is a subsection of this one. /// A should only have one active child at a time. - public JobProgressReporter CreateSection(string newStageName, double percentage) + public JobProgressReporter CreateSection(string? newStageName, double percentage) { if (percentage > 1 || percentage < 0) { From 280bbc836f561a4a16db03458cf9fa00c413635b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:06:55 -0500 Subject: [PATCH 284/717] Nullify `JobService` --- src/Tgstation.Server.Host/Jobs/IJobManager.cs | 2 +- src/Tgstation.Server.Host/Jobs/JobService.cs | 81 +++++++++---------- 2 files changed, 38 insertions(+), 45 deletions(-) diff --git a/src/Tgstation.Server.Host/Jobs/IJobManager.cs b/src/Tgstation.Server.Host/Jobs/IJobManager.cs index 58ad8eacd6d..9f582b34ab8 100644 --- a/src/Tgstation.Server.Host/Jobs/IJobManager.cs +++ b/src/Tgstation.Server.Host/Jobs/IJobManager.cs @@ -44,6 +44,6 @@ public interface IJobManager /// If the operation should wait until the job exits before completing. /// The for the operation. /// A resulting in the updated if it was cancelled, if it couldn't be found. - ValueTask CancelJob(Job job, User? user, bool blocking, CancellationToken cancellationToken); + ValueTask CancelJob(Job job, User? user, bool blocking, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Jobs/JobService.cs b/src/Tgstation.Server.Host/Jobs/JobService.cs index e383bf17460..cf4ed22abdf 100644 --- a/src/Tgstation.Server.Host/Jobs/JobService.cs +++ b/src/Tgstation.Server.Host/Jobs/JobService.cs @@ -21,8 +21,6 @@ using Tgstation.Server.Host.Utils; using Tgstation.Server.Host.Utils.SignalR; -#nullable disable - namespace Tgstation.Server.Host.Jobs { /// @@ -121,25 +119,19 @@ public async ValueTask RegisterOperation(Job job, JobEntrypoint operation, Cance ArgumentNullException.ThrowIfNull(job); ArgumentNullException.ThrowIfNull(operation); + if (job.StartedBy != null && job.StartedBy.Name == null) + throw new InvalidOperationException("StartedBy User associated with job does not have a Name!"); + job.StartedAt = DateTimeOffset.UtcNow; job.Cancelled = false; - if (job.StartedBy != null) - { - if (!job.StartedBy.Id.HasValue) - throw new InvalidOperationException("StartedBy User associated with job does not have an Id!"); - - if (job.StartedBy.Name == null) - throw new InvalidOperationException("StartedBy User associated with job does not have a Name!"); - } - var originalStartedBy = job.StartedBy; await databaseContextFactory.UseContext( async databaseContext => { job.Instance = new Models.Instance { - Id = job.Instance.Id.Value, + Id = job.Instance.Require(x => x.Id), }; databaseContext.Instances.Attach(job.Instance); @@ -149,14 +141,14 @@ await databaseContextFactory.UseContext( .GetTgsUser( dbUser => new User { - Id = dbUser.Id.Value, + Id = dbUser.Id!.Value, Name = dbUser.Name, }, cancellationToken); job.StartedBy = new User { - Id = originalStartedBy.Id.Value, + Id = originalStartedBy.Require(x => x.Id), }; databaseContext.Users.Attach(job.StartedBy); @@ -177,7 +169,7 @@ await databaseContextFactory.UseContext( bool jobShouldStart; lock (synchronizationLock) { - jobs.Add(job.Id.Value, jobHandler); + jobs.Add(job.Require(x => x.Id), jobHandler); jobShouldStart = !noMoreJobsShouldStart; } @@ -201,7 +193,7 @@ public Task StartAsync(CancellationToken cancellationToken) .Jobs .AsQueryable() .Where(y => !y.StoppedAt.HasValue) - .Select(y => y.Id.Value) + .Select(y => y.Id!.Value) .ToListAsync(cancellationToken); if (badJobIds.Count > 0) { @@ -224,7 +216,7 @@ public Task StartAsync(CancellationToken cancellationToken) /// public Task StopAsync(CancellationToken cancellationToken) { - List> joinTasks; + List> joinTasks; lock (addCancelLock) lock (synchronizationLock) { @@ -241,24 +233,25 @@ public Task StopAsync(CancellationToken cancellationToken) } /// - public async ValueTask CancelJob(Job job, User user, bool blocking, CancellationToken cancellationToken) + public async ValueTask CancelJob(Job job, User? user, bool blocking, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(job); - JobHandler handler; + var jid = job.Require(x => x.Id); + JobHandler? handler; lock (addCancelLock) { lock (synchronizationLock) - if (!jobs.TryGetValue(job.Id.Value, out handler)) + if (!jobs.TryGetValue(jid, out handler)) return null; - logger.LogDebug("Cancelling job ID {jobId}...", job.Id.Value); + logger.LogDebug("Cancelling job ID {jobId}...", jid); handler.Cancel(); // this will ensure the db update is only done once } await databaseContextFactory.UseContext(async databaseContext => { - var updatedJob = new Job(job.Id.Value); + var updatedJob = new Job(jid); databaseContext.Jobs.Attach(updatedJob); var attachedUser = user == null ? await databaseContext @@ -266,12 +259,12 @@ await databaseContextFactory.UseContext(async databaseContext => .GetTgsUser( dbUser => new User { - Id = dbUser.Id.Value, + Id = dbUser.Id!.Value, }, cancellationToken) : new User { - Id = user.Id.Value, + Id = user.Require(x => x.Id), }; databaseContext.Users.Attach(attachedUser); @@ -298,7 +291,7 @@ public void SetJobProgress(JobResponse apiResponse) ArgumentNullException.ThrowIfNull(apiResponse); lock (synchronizationLock) { - if (!jobs.TryGetValue(apiResponse.Id.Value, out var handler)) + if (!jobs.TryGetValue(apiResponse.Require(x => x.Id), out var handler)) return; apiResponse.Progress = handler.Progress; apiResponse.Stage = handler.Stage; @@ -306,18 +299,18 @@ public void SetJobProgress(JobResponse apiResponse) } /// - public async ValueTask WaitForJobCompletion(Job job, User canceller, CancellationToken jobCancellationToken, CancellationToken cancellationToken) + public async ValueTask WaitForJobCompletion(Job job, User? canceller, CancellationToken jobCancellationToken, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(job); if (!cancellationToken.CanBeCanceled) throw new ArgumentException("A cancellable CancellationToken should be provided!", nameof(cancellationToken)); - JobHandler handler; + JobHandler? handler; bool noMoreJobsShouldStart; lock (synchronizationLock) { - if (!jobs.TryGetValue(job.Id.Value, out handler)) + if (!jobs.TryGetValue(job.Require(x => x.Id), out handler)) return null; noMoreJobsShouldStart = this.noMoreJobsShouldStart; @@ -326,7 +319,7 @@ public void SetJobProgress(JobResponse apiResponse) if (noMoreJobsShouldStart && !handler.Started) await Extensions.TaskExtensions.InfiniteTask.WaitAsync(cancellationToken); - var cancelTask = ValueTask.FromResult(null); + var cancelTask = ValueTask.FromResult(null); bool result; using (jobCancellationToken.Register(() => cancelTask = CancelJob(job, canceller, true, cancellationToken))) result = await handler.Wait(cancellationToken); @@ -364,17 +357,18 @@ public void QueueActiveJobUpdates() async Task RunJob(Job job, JobEntrypoint operation, CancellationToken cancellationToken) #pragma warning restore CA1506 { - using (LogContext.PushProperty(SerilogContextHelper.JobIdContextProperty, job.Id)) + var jid = job.Require(x => x.Id); + using (LogContext.PushProperty(SerilogContextHelper.JobIdContextProperty, jid)) try { - void LogException(Exception ex) => logger.LogDebug(ex, "Job {jobId} exited with error!", job.Id); + void LogException(Exception ex) => logger.LogDebug(ex, "Job {jobId} exited with error!", jid); var hubUpdatesTask = Task.CompletedTask; var result = false; var firstLogHappened = false; var hubGroupName = JobsHub.HubGroupName(job); - Stopwatch stopwatch = null; + Stopwatch? stopwatch = null; void QueueHubUpdate(JobResponse update, bool final) { void NextUpdate(bool bypassRate) @@ -386,7 +380,7 @@ async Task ChainHubUpdate() if (!firstLogHappened) { - logger.LogTrace("Sending updates for job {id} to hub group {group}", update.Id.Value, hubGroupName); + logger.LogTrace("Sending updates for job {id} to hub group {group}", jid, hubGroupName); firstLogHappened = true; } @@ -397,7 +391,7 @@ await hub .ReceiveJobUpdate(update, CancellationToken.None); } - Stopwatch enteredLock = null; + Stopwatch? enteredLock = null; try { if (!bypassRate && stopwatch != null) @@ -418,19 +412,18 @@ await hub } } - var jobId = update.Id.Value; lock (hubUpdateActions) if (final) - hubUpdateActions.Remove(jobId); + hubUpdateActions.Remove(jid); else - hubUpdateActions[jobId] = () => NextUpdate(true); + hubUpdateActions[jid] = () => NextUpdate(true); NextUpdate(false); } try { - void UpdateProgress(string stage, double? progress) + void UpdateProgress(string? stage, double? progress) { if (progress.HasValue && (progress.Value < 0 || progress.Value > 1)) @@ -442,7 +435,7 @@ void UpdateProgress(string stage, double? progress) int? newProgress = progress.HasValue ? (int)Math.Floor(progress.Value * 100) : null; lock (synchronizationLock) - if (jobs.TryGetValue(job.Id.Value, out var handler)) + if (jobs.TryGetValue(jid, out var handler)) { handler.Stage = stage; handler.Progress = newProgress; @@ -492,7 +485,7 @@ await operation( { await databaseContextFactory.UseContext(async databaseContext => { - var attachedJob = new Job(job.Id.Value); + var attachedJob = new Job(jid); databaseContext.Jobs.Attach(attachedJob); attachedJob.StoppedAt = DateTimeOffset.UtcNow; @@ -517,7 +510,7 @@ await databaseContextFactory.UseContext(async databaseContext => .Include(x => x.Instance) .Include(x => x.StartedBy) .Include(x => x.CancelledBy) - .Where(dbJob => dbJob.Id == job.Id.Value) + .Where(dbJob => dbJob.Id == jid) .FirstAsync(CancellationToken.None); QueueHubUpdate(finalJob.ToApi(), true); }); @@ -525,7 +518,7 @@ await databaseContextFactory.UseContext(async databaseContext => catch { lock (hubUpdateActions) - hubUpdateActions.Remove(job.Id.Value); + hubUpdateActions.Remove(jid); throw; } @@ -545,8 +538,8 @@ await databaseContextFactory.UseContext(async databaseContext => { lock (synchronizationLock) { - var handler = jobs[job.Id.Value]; - jobs.Remove(job.Id.Value); + var handler = jobs[jid]; + jobs.Remove(jid); handler.Dispose(); } } From e8984f3178d09269e3b8799696a6cae41aeb9c49 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:07:33 -0500 Subject: [PATCH 285/717] Nullify `JobsHub` --- src/Tgstation.Server.Host/Jobs/JobsHub.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Jobs/JobsHub.cs b/src/Tgstation.Server.Host/Jobs/JobsHub.cs index 373fcc5af70..d11fdf79138 100644 --- a/src/Tgstation.Server.Host/Jobs/JobsHub.cs +++ b/src/Tgstation.Server.Host/Jobs/JobsHub.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils.SignalR; -#nullable disable - namespace Tgstation.Server.Host.Jobs { /// @@ -36,7 +34,7 @@ public static string HubGroupName(Job job) if (job.Instance == null) throw new InvalidOperationException("job.Instance was null!"); - return HubGroupName(job.Instance.Id.Value); + return HubGroupName(job.Instance.Require(x => x.Id)); } /// From 9c21854532b572d8204a3939a38e23f979afdd50 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:09:06 -0500 Subject: [PATCH 286/717] Nullify `JobsHubGroupMapper` --- .../Jobs/JobsHubGroupMapper.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs b/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs index 4fe5c710120..1342091caac 100644 --- a/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs +++ b/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs @@ -15,8 +15,6 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils.SignalR; -#nullable disable - namespace Tgstation.Server.Host.Jobs { /// @@ -119,20 +117,24 @@ async ValueTask MapConnectionGroups( { ArgumentNullException.ThrowIfNull(authenticationContext); - logger.LogTrace("MapConnectionGroups UID: {uid}", authenticationContext.User.Id.Value); + var pid = authenticationContext.PermissionSet.Require(x => x.Id); + logger.LogTrace( + "MapConnectionGroups UID: {uid} PID: {pid}", + authenticationContext.User.Require(x => x.Id), + pid); - List permedInstanceIds = null; + List? permedInstanceIds = null; await databaseContextFactory.UseContext( async databaseContext => permedInstanceIds = await databaseContext .InstancePermissionSets .AsQueryable() - .Where(ips => ips.PermissionSetId == authenticationContext.PermissionSet.Id.Value) + .Where(ips => ips.PermissionSetId == pid) .Select(ips => ips.InstanceId) .ToListAsync(cancellationToken)); await mappingFunc( - permedInstanceIds.Select( + permedInstanceIds!.Select( JobsHub.HubGroupName)); jobsHubUpdater.QueueActiveJobUpdates(); @@ -156,7 +158,7 @@ ValueTask RefreshHubGroups(long permissionSetId, CancellationToken cancellationT var allInstanceIds = await databaseContext .Instances .Select( - instance => instance.Id.Value) + instance => instance.Id!.Value) .ToListAsync(cancellationToken); var permissionSetAccessibleInstanceIds = await databaseContext .InstancePermissionSets From 07a19988cfcc1c475cabdf19eb7fecd2c16afe27 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:09:35 -0500 Subject: [PATCH 287/717] Nullify `DesignTimeDbContextFactoryHelpers` --- .../Database/Design/DesignTimeDbContextFactoryHelpers.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs b/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs index b8527648bbd..126dfbef4a5 100644 --- a/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs +++ b/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Database.Design { /// @@ -23,7 +21,7 @@ static class DesignTimeDbContextFactoryHelpers public static DbContextOptions CreateDatabaseContextOptions( DatabaseType databaseType, string connectionString, - string serverVersion = null) + string? serverVersion = null) where TDatabaseContext : DatabaseContext { var dbConfig = new DatabaseConfiguration From 5863410a67e5a275cbdf641aa01ea9bf6b73c185 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:10:20 -0500 Subject: [PATCH 288/717] Nullify `IDesignTimeDbContextFactory`s --- .../Database/Design/MySqlDesignTimeDbContextFactory.cs | 2 -- .../Database/Design/PostgresSqlDesignTimeDbContextFactory.cs | 2 -- .../Database/Design/SqlServerDesignTimeDbContextFactory.cs | 2 -- .../Database/Design/SqliteDesignTimeDbContextFactory.cs | 2 -- 4 files changed, 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs index 86efd5568f8..f67028efffc 100644 --- a/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Database.Design { /// diff --git a/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs index 11151e5e582..965eade13e1 100644 --- a/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/Design/PostgresSqlDesignTimeDbContextFactory.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Common; using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Database.Design { /// diff --git a/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs index ac0704df2a6..9b5623725e1 100644 --- a/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Database.Design { /// diff --git a/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs index f4c36cb31fb..924d8934f99 100644 --- a/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Database.Design { /// From 1b68d408b5d8679e14159a74963a9bed07dee416 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:12:54 -0500 Subject: [PATCH 289/717] Nullify migrations --- .../20230331220749_MSAddDreamDaemonLogOutput.Designer.cs | 2 -- .../Migrations/20230331220749_MSAddDreamDaemonLogOutput.cs | 2 -- .../20230331221032_PGAddDreamDaemonLogOutput.Designer.cs | 2 -- .../Migrations/20230331221032_PGAddDreamDaemonLogOutput.cs | 2 -- .../20230331221156_SLAddDreamDaemonLogOutput.Designer.cs | 2 -- .../Migrations/20230331221156_SLAddDreamDaemonLogOutput.cs | 2 -- .../20230401210715_MYAddDreamDaemonLogOutput.Designer.cs | 2 -- .../Migrations/20230401210715_MYAddDreamDaemonLogOutput.cs | 2 -- ...0230403050623_MSAddReattachInfoInitialCompileJob.Designer.cs | 2 -- .../20230403050623_MSAddReattachInfoInitialCompileJob.cs | 2 -- ...0230403050737_MYAddReattachInfoInitialCompileJob.Designer.cs | 2 -- .../20230403050737_MYAddReattachInfoInitialCompileJob.cs | 2 -- ...0230403050832_PGAddReattachInfoInitialCompileJob.Designer.cs | 2 -- .../20230403050832_PGAddReattachInfoInitialCompileJob.cs | 2 -- ...0230403050941_SLAddReattachInfoInitialCompileJob.Designer.cs | 2 -- .../20230403050941_SLAddReattachInfoInitialCompileJob.cs | 2 -- .../Migrations/20230520203236_MSAddSystemChannels.Designer.cs | 2 -- .../Database/Migrations/20230520203236_MSAddSystemChannels.cs | 2 -- .../Migrations/20230520203305_MYAddSystemChannels.Designer.cs | 2 -- .../Database/Migrations/20230520203305_MYAddSystemChannels.cs | 2 -- .../Migrations/20230520203332_PGAddSystemChannels.Designer.cs | 2 -- .../Database/Migrations/20230520203332_PGAddSystemChannels.cs | 2 -- .../Migrations/20230520203402_SLAddSystemChannels.Designer.cs | 2 -- .../Database/Migrations/20230520203402_SLAddSystemChannels.cs | 2 -- .../20230614053739_MSRenameHeartbeatsToHealthChecks.Designer.cs | 2 -- .../20230614053739_MSRenameHeartbeatsToHealthChecks.cs | 2 -- .../20230614053927_MYRenameHeartbeatsToHealthChecks.Designer.cs | 2 -- .../20230614053927_MYRenameHeartbeatsToHealthChecks.cs | 2 -- .../20230614054432_PGRenameHeartbeatsToHealthChecks.Designer.cs | 2 -- .../20230614054432_PGRenameHeartbeatsToHealthChecks.cs | 2 -- .../20230614054537_SLRenameHeartbeatsToHealthChecks.Designer.cs | 2 -- .../20230614054537_SLRenameHeartbeatsToHealthChecks.cs | 2 -- .../Migrations/20230622020600_MSAddMapThreads.Designer.cs | 2 -- .../Database/Migrations/20230622020600_MSAddMapThreads.cs | 2 -- .../Migrations/20230622020623_MYAddMapThreads.Designer.cs | 2 -- .../Database/Migrations/20230622020623_MYAddMapThreads.cs | 2 -- .../Migrations/20230622020647_PGAddMapThreads.Designer.cs | 2 -- .../Database/Migrations/20230622020647_PGAddMapThreads.cs | 2 -- .../Migrations/20230622020712_SLAddMapThreads.Designer.cs | 2 -- .../Database/Migrations/20230622020712_SLAddMapThreads.cs | 2 -- .../Migrations/20231105004801_MSAddJobCodes.Designer.cs | 2 -- .../Database/Migrations/20231105004801_MSAddJobCodes.cs | 2 -- .../Migrations/20231105004808_MYAddJobCodes.Designer.cs | 2 -- .../Database/Migrations/20231105004808_MYAddJobCodes.cs | 2 -- .../Migrations/20231105004814_PGAddJobCodes.Designer.cs | 2 -- .../Database/Migrations/20231105004814_PGAddJobCodes.cs | 2 -- .../Migrations/20231105004820_SLAddJobCodes.Designer.cs | 2 -- .../Database/Migrations/20231105004820_SLAddJobCodes.cs | 2 -- .../20231108004349_MSRenameByondColumnsToEngine.Designer.cs | 2 -- .../Migrations/20231108004349_MSRenameByondColumnsToEngine.cs | 2 -- .../20231108004356_MYRenameByondColumnsToEngine.Designer.cs | 2 -- .../Migrations/20231108004356_MYRenameByondColumnsToEngine.cs | 2 -- .../20231108004402_PGRenameByondColumnsToEngine.Designer.cs | 2 -- .../Migrations/20231108004402_PGRenameByondColumnsToEngine.cs | 2 -- .../20231108004409_SLRenameByondColumnsToEngine.Designer.cs | 2 -- .../Migrations/20231108004409_SLRenameByondColumnsToEngine.cs | 2 -- .../Database/Migrations/MySqlDatabaseContextModelSnapshot.cs | 2 -- .../Migrations/PostgresSqlDatabaseContextModelSnapshot.cs | 2 -- .../Migrations/SqlServerDatabaseContextModelSnapshot.cs | 2 -- .../Database/Migrations/SqliteDatabaseContextModelSnapshot.cs | 2 -- 60 files changed, 120 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.Designer.cs index 02be0acad16..8bc0ff72d47 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqlServerDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.cs index bc8e3d1880f..b2d86c3ae76 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331220749_MSAddDreamDaemonLogOutput.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.Designer.cs index c1bb3e23c5f..adca6dbfa74 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(PostgresSqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.cs index 1828f867bba..cded945a221 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331221032_PGAddDreamDaemonLogOutput.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.Designer.cs index 1e7c30621fb..2610389f7e0 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqliteDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.cs b/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.cs index 587dbf9aa24..f574ac0195a 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230331221156_SLAddDreamDaemonLogOutput.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230401210715_MYAddDreamDaemonLogOutput.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230401210715_MYAddDreamDaemonLogOutput.Designer.cs index 69acf576b12..aa0b1d70c11 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230401210715_MYAddDreamDaemonLogOutput.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230401210715_MYAddDreamDaemonLogOutput.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(MySqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230401210715_MYAddDreamDaemonLogOutput.cs b/src/Tgstation.Server.Host/Database/Migrations/20230401210715_MYAddDreamDaemonLogOutput.cs index 2b023f5fa24..18fc203d23f 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230401210715_MYAddDreamDaemonLogOutput.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230401210715_MYAddDreamDaemonLogOutput.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230403050623_MSAddReattachInfoInitialCompileJob.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230403050623_MSAddReattachInfoInitialCompileJob.Designer.cs index f7499925800..d1c93465d63 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230403050623_MSAddReattachInfoInitialCompileJob.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230403050623_MSAddReattachInfoInitialCompileJob.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqlServerDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230403050623_MSAddReattachInfoInitialCompileJob.cs b/src/Tgstation.Server.Host/Database/Migrations/20230403050623_MSAddReattachInfoInitialCompileJob.cs index 2c378335d75..2fa00301433 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230403050623_MSAddReattachInfoInitialCompileJob.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230403050623_MSAddReattachInfoInitialCompileJob.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230403050737_MYAddReattachInfoInitialCompileJob.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230403050737_MYAddReattachInfoInitialCompileJob.Designer.cs index a53708cfc02..e5a7f0400b8 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230403050737_MYAddReattachInfoInitialCompileJob.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230403050737_MYAddReattachInfoInitialCompileJob.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(MySqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230403050737_MYAddReattachInfoInitialCompileJob.cs b/src/Tgstation.Server.Host/Database/Migrations/20230403050737_MYAddReattachInfoInitialCompileJob.cs index da962107e12..3dc01170b72 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230403050737_MYAddReattachInfoInitialCompileJob.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230403050737_MYAddReattachInfoInitialCompileJob.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230403050832_PGAddReattachInfoInitialCompileJob.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230403050832_PGAddReattachInfoInitialCompileJob.Designer.cs index 8e4962a1e08..3129b863f99 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230403050832_PGAddReattachInfoInitialCompileJob.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230403050832_PGAddReattachInfoInitialCompileJob.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(PostgresSqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230403050832_PGAddReattachInfoInitialCompileJob.cs b/src/Tgstation.Server.Host/Database/Migrations/20230403050832_PGAddReattachInfoInitialCompileJob.cs index 14d08913ec0..bab6bbc9c1e 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230403050832_PGAddReattachInfoInitialCompileJob.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230403050832_PGAddReattachInfoInitialCompileJob.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230403050941_SLAddReattachInfoInitialCompileJob.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230403050941_SLAddReattachInfoInitialCompileJob.Designer.cs index 8330e52cb1c..3ac89843099 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230403050941_SLAddReattachInfoInitialCompileJob.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230403050941_SLAddReattachInfoInitialCompileJob.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqliteDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230403050941_SLAddReattachInfoInitialCompileJob.cs b/src/Tgstation.Server.Host/Database/Migrations/20230403050941_SLAddReattachInfoInitialCompileJob.cs index 630411174d5..91f1ea6bb8e 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230403050941_SLAddReattachInfoInitialCompileJob.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230403050941_SLAddReattachInfoInitialCompileJob.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230520203236_MSAddSystemChannels.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230520203236_MSAddSystemChannels.Designer.cs index 4fa9364f35f..23b628d9c88 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230520203236_MSAddSystemChannels.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230520203236_MSAddSystemChannels.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqlServerDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230520203236_MSAddSystemChannels.cs b/src/Tgstation.Server.Host/Database/Migrations/20230520203236_MSAddSystemChannels.cs index 410d150c1e1..3ab2299fe55 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230520203236_MSAddSystemChannels.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230520203236_MSAddSystemChannels.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230520203305_MYAddSystemChannels.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230520203305_MYAddSystemChannels.Designer.cs index 3f1e7b32494..2a7dbd32d8a 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230520203305_MYAddSystemChannels.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230520203305_MYAddSystemChannels.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(MySqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230520203305_MYAddSystemChannels.cs b/src/Tgstation.Server.Host/Database/Migrations/20230520203305_MYAddSystemChannels.cs index ec249f3e446..691e439fdca 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230520203305_MYAddSystemChannels.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230520203305_MYAddSystemChannels.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230520203332_PGAddSystemChannels.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230520203332_PGAddSystemChannels.Designer.cs index 613cd8034ef..cecc00d99f6 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230520203332_PGAddSystemChannels.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230520203332_PGAddSystemChannels.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(PostgresSqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230520203332_PGAddSystemChannels.cs b/src/Tgstation.Server.Host/Database/Migrations/20230520203332_PGAddSystemChannels.cs index 60bf1c52297..17df0a48ef5 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230520203332_PGAddSystemChannels.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230520203332_PGAddSystemChannels.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230520203402_SLAddSystemChannels.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230520203402_SLAddSystemChannels.Designer.cs index fbe9ae470e3..2fbf1587188 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230520203402_SLAddSystemChannels.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230520203402_SLAddSystemChannels.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqliteDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230520203402_SLAddSystemChannels.cs b/src/Tgstation.Server.Host/Database/Migrations/20230520203402_SLAddSystemChannels.cs index 4dc47740e86..95dc26a1b80 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230520203402_SLAddSystemChannels.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230520203402_SLAddSystemChannels.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230614053739_MSRenameHeartbeatsToHealthChecks.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230614053739_MSRenameHeartbeatsToHealthChecks.Designer.cs index 0b7c9281fb4..af40476708d 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230614053739_MSRenameHeartbeatsToHealthChecks.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230614053739_MSRenameHeartbeatsToHealthChecks.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqlServerDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230614053739_MSRenameHeartbeatsToHealthChecks.cs b/src/Tgstation.Server.Host/Database/Migrations/20230614053739_MSRenameHeartbeatsToHealthChecks.cs index 37dbc148166..20f53e2d0a4 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230614053739_MSRenameHeartbeatsToHealthChecks.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230614053739_MSRenameHeartbeatsToHealthChecks.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230614053927_MYRenameHeartbeatsToHealthChecks.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230614053927_MYRenameHeartbeatsToHealthChecks.Designer.cs index 78f17b9159e..ce9233fc4e5 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230614053927_MYRenameHeartbeatsToHealthChecks.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230614053927_MYRenameHeartbeatsToHealthChecks.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(MySqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230614053927_MYRenameHeartbeatsToHealthChecks.cs b/src/Tgstation.Server.Host/Database/Migrations/20230614053927_MYRenameHeartbeatsToHealthChecks.cs index 37d18bf1fb0..25fb3f21c80 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230614053927_MYRenameHeartbeatsToHealthChecks.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230614053927_MYRenameHeartbeatsToHealthChecks.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230614054432_PGRenameHeartbeatsToHealthChecks.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230614054432_PGRenameHeartbeatsToHealthChecks.Designer.cs index 650e56fe66d..849210b5854 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230614054432_PGRenameHeartbeatsToHealthChecks.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230614054432_PGRenameHeartbeatsToHealthChecks.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(PostgresSqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230614054432_PGRenameHeartbeatsToHealthChecks.cs b/src/Tgstation.Server.Host/Database/Migrations/20230614054432_PGRenameHeartbeatsToHealthChecks.cs index 5ccae3445bb..75e99990d91 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230614054432_PGRenameHeartbeatsToHealthChecks.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230614054432_PGRenameHeartbeatsToHealthChecks.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230614054537_SLRenameHeartbeatsToHealthChecks.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230614054537_SLRenameHeartbeatsToHealthChecks.Designer.cs index 9180386ff12..9ffc8607f92 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230614054537_SLRenameHeartbeatsToHealthChecks.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230614054537_SLRenameHeartbeatsToHealthChecks.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqliteDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230614054537_SLRenameHeartbeatsToHealthChecks.cs b/src/Tgstation.Server.Host/Database/Migrations/20230614054537_SLRenameHeartbeatsToHealthChecks.cs index dc88c94012c..8326dca934b 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230614054537_SLRenameHeartbeatsToHealthChecks.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230614054537_SLRenameHeartbeatsToHealthChecks.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230622020600_MSAddMapThreads.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230622020600_MSAddMapThreads.Designer.cs index 09c34848021..8910b644ac2 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230622020600_MSAddMapThreads.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230622020600_MSAddMapThreads.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqlServerDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230622020600_MSAddMapThreads.cs b/src/Tgstation.Server.Host/Database/Migrations/20230622020600_MSAddMapThreads.cs index dab10dc6af1..2bfc981d34a 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230622020600_MSAddMapThreads.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230622020600_MSAddMapThreads.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230622020623_MYAddMapThreads.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230622020623_MYAddMapThreads.Designer.cs index f7039334cf4..b9fe9c7cdd4 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230622020623_MYAddMapThreads.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230622020623_MYAddMapThreads.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(MySqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230622020623_MYAddMapThreads.cs b/src/Tgstation.Server.Host/Database/Migrations/20230622020623_MYAddMapThreads.cs index 1f83abc44d4..aa52cc0d6ba 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230622020623_MYAddMapThreads.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230622020623_MYAddMapThreads.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230622020647_PGAddMapThreads.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230622020647_PGAddMapThreads.Designer.cs index 6ef71f98eea..37c731af707 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230622020647_PGAddMapThreads.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230622020647_PGAddMapThreads.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(PostgresSqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230622020647_PGAddMapThreads.cs b/src/Tgstation.Server.Host/Database/Migrations/20230622020647_PGAddMapThreads.cs index 1ff154f4489..12314271580 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230622020647_PGAddMapThreads.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230622020647_PGAddMapThreads.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230622020712_SLAddMapThreads.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20230622020712_SLAddMapThreads.Designer.cs index 0db22004a66..23859c77bed 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230622020712_SLAddMapThreads.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230622020712_SLAddMapThreads.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqliteDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20230622020712_SLAddMapThreads.cs b/src/Tgstation.Server.Host/Database/Migrations/20230622020712_SLAddMapThreads.cs index 218c9d7d4bc..8909a495d28 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20230622020712_SLAddMapThreads.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20230622020712_SLAddMapThreads.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231105004801_MSAddJobCodes.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231105004801_MSAddJobCodes.Designer.cs index 556f6d1009d..3d2f9959ab7 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231105004801_MSAddJobCodes.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231105004801_MSAddJobCodes.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqlServerDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231105004801_MSAddJobCodes.cs b/src/Tgstation.Server.Host/Database/Migrations/20231105004801_MSAddJobCodes.cs index 87636a060f9..4a6606334ac 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231105004801_MSAddJobCodes.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231105004801_MSAddJobCodes.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231105004808_MYAddJobCodes.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231105004808_MYAddJobCodes.Designer.cs index c5f5fb94dcc..197b2441731 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231105004808_MYAddJobCodes.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231105004808_MYAddJobCodes.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(MySqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231105004808_MYAddJobCodes.cs b/src/Tgstation.Server.Host/Database/Migrations/20231105004808_MYAddJobCodes.cs index 61eb53b6a5d..4afb9021831 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231105004808_MYAddJobCodes.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231105004808_MYAddJobCodes.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231105004814_PGAddJobCodes.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231105004814_PGAddJobCodes.Designer.cs index 6ad0149338d..501367d6fc3 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231105004814_PGAddJobCodes.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231105004814_PGAddJobCodes.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(PostgresSqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231105004814_PGAddJobCodes.cs b/src/Tgstation.Server.Host/Database/Migrations/20231105004814_PGAddJobCodes.cs index 5bd1b863f68..b11ba1b584c 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231105004814_PGAddJobCodes.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231105004814_PGAddJobCodes.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231105004820_SLAddJobCodes.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231105004820_SLAddJobCodes.Designer.cs index 718743a339c..7fb555cc8b8 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231105004820_SLAddJobCodes.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231105004820_SLAddJobCodes.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqliteDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231105004820_SLAddJobCodes.cs b/src/Tgstation.Server.Host/Database/Migrations/20231105004820_SLAddJobCodes.cs index 76a2be02ee4..77076a8361b 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231105004820_SLAddJobCodes.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231105004820_SLAddJobCodes.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231108004349_MSRenameByondColumnsToEngine.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231108004349_MSRenameByondColumnsToEngine.Designer.cs index 65b94a6fc7d..99cdc64c2e5 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231108004349_MSRenameByondColumnsToEngine.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231108004349_MSRenameByondColumnsToEngine.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqlServerDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231108004349_MSRenameByondColumnsToEngine.cs b/src/Tgstation.Server.Host/Database/Migrations/20231108004349_MSRenameByondColumnsToEngine.cs index b142ab007b5..cdf156ec28c 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231108004349_MSRenameByondColumnsToEngine.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231108004349_MSRenameByondColumnsToEngine.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231108004356_MYRenameByondColumnsToEngine.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231108004356_MYRenameByondColumnsToEngine.Designer.cs index ff843c5a049..841a10d43df 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231108004356_MYRenameByondColumnsToEngine.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231108004356_MYRenameByondColumnsToEngine.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(MySqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231108004356_MYRenameByondColumnsToEngine.cs b/src/Tgstation.Server.Host/Database/Migrations/20231108004356_MYRenameByondColumnsToEngine.cs index 844b027d164..00a5d1fe1c2 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231108004356_MYRenameByondColumnsToEngine.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231108004356_MYRenameByondColumnsToEngine.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231108004402_PGRenameByondColumnsToEngine.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231108004402_PGRenameByondColumnsToEngine.Designer.cs index 2689c8ae295..7f755e8876e 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231108004402_PGRenameByondColumnsToEngine.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231108004402_PGRenameByondColumnsToEngine.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(PostgresSqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231108004402_PGRenameByondColumnsToEngine.cs b/src/Tgstation.Server.Host/Database/Migrations/20231108004402_PGRenameByondColumnsToEngine.cs index 32a4a0957e6..4766b285e80 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231108004402_PGRenameByondColumnsToEngine.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231108004402_PGRenameByondColumnsToEngine.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231108004409_SLRenameByondColumnsToEngine.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231108004409_SLRenameByondColumnsToEngine.Designer.cs index f34889c73cd..dae9036d079 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231108004409_SLRenameByondColumnsToEngine.Designer.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231108004409_SLRenameByondColumnsToEngine.Designer.cs @@ -5,8 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqliteDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231108004409_SLRenameByondColumnsToEngine.cs b/src/Tgstation.Server.Host/Database/Migrations/20231108004409_SLRenameByondColumnsToEngine.cs index 755fc8d06ee..3b95c6433c1 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/20231108004409_SLRenameByondColumnsToEngine.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/20231108004409_SLRenameByondColumnsToEngine.cs @@ -2,8 +2,6 @@ using Microsoft.EntityFrameworkCore.Migrations; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { /// diff --git a/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs index 713ce53b72f..e470e52b3cf 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs @@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(MySqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs index 5e872a384a8..96f60f68507 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs @@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(PostgresSqlDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs index cce95499021..30050cf7899 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs @@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqlServerDatabaseContext))] diff --git a/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs index 3c0504bde5b..3f4daecc39b 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs @@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -#nullable disable - namespace Tgstation.Server.Host.Database.Migrations { [DbContext(typeof(SqliteDatabaseContext))] From 51fd04953efb76ae306b57abec087d4b5a89b3e4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:13:15 -0500 Subject: [PATCH 290/717] Nullify `DatabaseCollection` --- src/Tgstation.Server.Host/Database/DatabaseCollection.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/DatabaseCollection.cs b/src/Tgstation.Server.Host/Database/DatabaseCollection.cs index 831772335bb..b2dafa719dc 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseCollection.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseCollection.cs @@ -7,8 +7,6 @@ using Microsoft.EntityFrameworkCore; -#nullable disable - namespace Tgstation.Server.Host.Database { /// From 6c50b3314761be5fe60ef026add2d4461a18ddbb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:13:27 -0500 Subject: [PATCH 291/717] Nullify `DatabaseConnectionFactory` --- src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs b/src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs index 7cc0e2e5ed0..b118f346dbb 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseConnectionFactory.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Database { /// From bc80713a9520dd5bf45eb808c117e5feef931559 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:14:17 -0500 Subject: [PATCH 292/717] Nullify `DatabaseContext` --- .../Database/DatabaseContext.cs | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/DatabaseContext.cs b/src/Tgstation.Server.Host/Database/DatabaseContext.cs index 6b1ce65d232..a98fb1c1805 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseContext.cs @@ -15,8 +15,6 @@ using Tgstation.Server.Host.Database.Migrations; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Database { /// @@ -262,21 +260,21 @@ public static Action GetConfigur protected DatabaseContext(DbContextOptions dbContextOptions) : base(dbContextOptions) { - usersCollection = new DatabaseCollection(Users); - instancesCollection = new DatabaseCollection(Instances); - instancePermissionSetsCollection = new DatabaseCollection(InstancePermissionSets); - compileJobsCollection = new DatabaseCollection(CompileJobs); - repositorySettingsCollection = new DatabaseCollection(RepositorySettings); - dreamMakerSettingsCollection = new DatabaseCollection(DreamMakerSettings); - dreamDaemonSettingsCollection = new DatabaseCollection(DreamDaemonSettings); - chatBotsCollection = new DatabaseCollection(ChatBots); - chatChannelsCollection = new DatabaseCollection(ChatChannels); - revisionInformationsCollection = new DatabaseCollection(RevisionInformations); - jobsCollection = new DatabaseCollection(Jobs); - reattachInformationsCollection = new DatabaseCollection(ReattachInformations); - oAuthConnections = new DatabaseCollection(OAuthConnections); - groups = new DatabaseCollection(Groups); - permissionSets = new DatabaseCollection(PermissionSets); + usersCollection = new DatabaseCollection(Users!); + instancesCollection = new DatabaseCollection(Instances!); + instancePermissionSetsCollection = new DatabaseCollection(InstancePermissionSets!); + compileJobsCollection = new DatabaseCollection(CompileJobs!); + repositorySettingsCollection = new DatabaseCollection(RepositorySettings!); + dreamMakerSettingsCollection = new DatabaseCollection(DreamMakerSettings!); + dreamDaemonSettingsCollection = new DatabaseCollection(DreamDaemonSettings!); + chatBotsCollection = new DatabaseCollection(ChatBots!); + chatChannelsCollection = new DatabaseCollection(ChatChannels!); + revisionInformationsCollection = new DatabaseCollection(RevisionInformations!); + jobsCollection = new DatabaseCollection(Jobs!); + reattachInformationsCollection = new DatabaseCollection(ReattachInformations!); + oAuthConnections = new DatabaseCollection(OAuthConnections!); + groups = new DatabaseCollection(Groups!); + permissionSets = new DatabaseCollection(PermissionSets!); } /// @@ -420,7 +418,7 @@ public async ValueTask SchemaDowngradeForServerVersion( throw new NotSupportedException("Cannot migrate below version 4.1.0!"); // Update this with new migrations as they are made - string targetMigration = null; + string? targetMigration = null; string BadDatabaseType() => throw new ArgumentException($"Invalid DatabaseType: {currentDatabaseType}", nameof(currentDatabaseType)); From f23d32f36c5519180152722901976f1ec828721b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:15:16 -0500 Subject: [PATCH 293/717] Nullify `DatabaseContextFactory` --- src/Tgstation.Server.Host/Database/DatabaseContextFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/DatabaseContextFactory.cs b/src/Tgstation.Server.Host/Database/DatabaseContextFactory.cs index 854bc6ea65c..b04e32858b3 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseContextFactory.cs @@ -3,8 +3,6 @@ using Microsoft.Extensions.DependencyInjection; -#nullable disable - namespace Tgstation.Server.Host.Database { /// From e5b55f07aa45c94e0d0e6baef099334868561686 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:18:26 -0500 Subject: [PATCH 294/717] Nullify `DatabaseSeeder` --- src/Tgstation.Server.Host/Database/DatabaseSeeder.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs b/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs index 51bf71bc6d3..c88c7a5e0d3 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs @@ -16,8 +16,6 @@ using Z.EntityFramework.Plus; -#nullable disable - namespace Tgstation.Server.Host.Database { /// @@ -59,7 +57,7 @@ sealed class DatabaseSeeder : IDatabaseSeeder /// The to add a system to. /// An existing , if any. /// The created system . - static User SeedSystemUser(IDatabaseContext databaseContext, User tgsUser = null) + static User SeedSystemUser(IDatabaseContext databaseContext, User? tgsUser = null) { bool alreadyExists = tgsUser != null; tgsUser ??= new User() @@ -233,7 +231,7 @@ async ValueTask SanitizeDatabase(IDatabaseContext databaseContext, CancellationT .AsQueryable() .ToListAsync(cancellationToken); foreach (var instance in allInstances) - instance.Path = instance.Path.Replace('\\', '/'); + instance.Path = instance.Path!.Replace('\\', '/'); } if (generalConfiguration.ByondTopicTimeout != 0) @@ -305,7 +303,7 @@ async ValueTask ResetAdminPassword(IDatabaseContext databaseContext, Cancellatio /// The to use. /// The for the operation. /// A resulting in the admin or . If , must be called on . - async ValueTask GetAdminUser(IDatabaseContext databaseContext, CancellationToken cancellationToken) + async ValueTask GetAdminUser(IDatabaseContext databaseContext, CancellationToken cancellationToken) { var admin = await databaseContext .Users From d8e0e1f3e653f30379e4cddcc902981560ca1ec1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:18:45 -0500 Subject: [PATCH 295/717] Nullify `IDatabaseCollection` --- src/Tgstation.Server.Host/Database/IDatabaseCollection.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/IDatabaseCollection.cs b/src/Tgstation.Server.Host/Database/IDatabaseCollection.cs index 08df6330f9a..a9e1fe0e03c 100644 --- a/src/Tgstation.Server.Host/Database/IDatabaseCollection.cs +++ b/src/Tgstation.Server.Host/Database/IDatabaseCollection.cs @@ -1,8 +1,6 @@ using System.Collections.Generic; using System.Linq; -#nullable disable - namespace Tgstation.Server.Host.Database { /// From 34f8f2c63bc85286df5223972a04a4f4cc225c4d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:18:59 -0500 Subject: [PATCH 296/717] Nullify `IDatabaseConnectionFactory` --- .../Database/IDatabaseConnectionFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/IDatabaseConnectionFactory.cs b/src/Tgstation.Server.Host/Database/IDatabaseConnectionFactory.cs index 7ce5ba0f5f0..abea5f17026 100644 --- a/src/Tgstation.Server.Host/Database/IDatabaseConnectionFactory.cs +++ b/src/Tgstation.Server.Host/Database/IDatabaseConnectionFactory.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Database { /// From 46712f5f229d2f5fe46a8bbbf1a26ea411be883e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:19:16 -0500 Subject: [PATCH 297/717] Nullify `IDatabaseContext` --- src/Tgstation.Server.Host/Database/IDatabaseContext.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/IDatabaseContext.cs b/src/Tgstation.Server.Host/Database/IDatabaseContext.cs index dc276cf371c..00b90298c67 100644 --- a/src/Tgstation.Server.Host/Database/IDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/IDatabaseContext.cs @@ -8,8 +8,6 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Database { /// From b6cc749dd9e0ed59f3756d59117dbd00b08cc8d3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:19:34 -0500 Subject: [PATCH 298/717] Nullift `IDatabaseContextFactory` --- src/Tgstation.Server.Host/Database/IDatabaseContextFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/IDatabaseContextFactory.cs b/src/Tgstation.Server.Host/Database/IDatabaseContextFactory.cs index a51906ff409..4004c873c08 100644 --- a/src/Tgstation.Server.Host/Database/IDatabaseContextFactory.cs +++ b/src/Tgstation.Server.Host/Database/IDatabaseContextFactory.cs @@ -1,8 +1,6 @@ using System; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Database { /// From eb16e393c806337977d446cdbe2c25d5edf487d9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:19:51 -0500 Subject: [PATCH 299/717] Nullify `IDatabaseSeeder` --- src/Tgstation.Server.Host/Database/IDatabaseSeeder.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/IDatabaseSeeder.cs b/src/Tgstation.Server.Host/Database/IDatabaseSeeder.cs index 76c0761fb91..e888b0093a8 100644 --- a/src/Tgstation.Server.Host/Database/IDatabaseSeeder.cs +++ b/src/Tgstation.Server.Host/Database/IDatabaseSeeder.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Database { /// From 99a0e21be4dc0da87a6faf39c0c81250e7b446bf Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:20:34 -0500 Subject: [PATCH 300/717] Nullify `DatabaseContext` overrides --- src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs | 2 -- .../Database/PostgresSqlDatabaseContext.cs | 2 -- src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs | 2 -- src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs | 2 -- 4 files changed, 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs b/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs index 68112d5fb2c..4bdcf9a066d 100644 --- a/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/MySqlDatabaseContext.cs @@ -8,8 +8,6 @@ using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/PostgresSqlDatabaseContext.cs b/src/Tgstation.Server.Host/Database/PostgresSqlDatabaseContext.cs index 952f515347d..d9157ab41a5 100644 --- a/src/Tgstation.Server.Host/Database/PostgresSqlDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/PostgresSqlDatabaseContext.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs b/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs index 10e1f6d16ff..3997e0a46b3 100644 --- a/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/SqlServerDatabaseContext.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Database { /// diff --git a/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs b/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs index 1a35d2e7697..98a58190d91 100644 --- a/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/SqliteDatabaseContext.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Database { /// From cdee693be916dd03e7fcccffa5841d57cbb5a17d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:22:03 -0500 Subject: [PATCH 301/717] Nullify `BoolConverter` --- .../Extensions/Converters/BoolConverter.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/Converters/BoolConverter.cs b/src/Tgstation.Server.Host/Extensions/Converters/BoolConverter.cs index 502980a212b..7812072f4a9 100644 --- a/src/Tgstation.Server.Host/Extensions/Converters/BoolConverter.cs +++ b/src/Tgstation.Server.Host/Extensions/Converters/BoolConverter.cs @@ -2,8 +2,6 @@ using Newtonsoft.Json; -#nullable disable - namespace Tgstation.Server.Host.Extensions.Converters { /// @@ -12,10 +10,18 @@ namespace Tgstation.Server.Host.Extensions.Converters sealed class BoolConverter : JsonConverter { /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => writer.WriteValue(((bool)value) ? 1 : 0); + public override void WriteJson(JsonWriter? writer, object? value, JsonSerializer serializer) + { + ArgumentNullException.ThrowIfNull(writer); + writer.WriteValue(((bool)value!) ? 1 : 0); + } /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => reader.Value.ToString() == "1"; + public override object? ReadJson(JsonReader? reader, Type? objectType, object? existingValue, JsonSerializer serializer) + { + ArgumentNullException.ThrowIfNull(reader); + return reader.Value!.ToString() == "1"; + } /// public override bool CanConvert(Type objectType) => objectType == typeof(bool); From 8f1dfe99c03882a2c7c32ffd5297bd42ed078792 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:23:24 -0500 Subject: [PATCH 302/717] Nullify `VersionConverter` --- .../Extensions/Converters/VersionConverter.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs b/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs index e1bf992cab2..48c593d72fb 100644 --- a/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs +++ b/src/Tgstation.Server.Host/Extensions/Converters/VersionConverter.cs @@ -8,8 +8,6 @@ using YamlDotNet.Core.Events; using YamlDotNet.Serialization; -#nullable disable - namespace Tgstation.Server.Host.Extensions.Converters { /// @@ -23,7 +21,7 @@ public sealed class VersionConverter : JsonConverter, IYamlTypeConverter /// The to check. /// If the method should if validation fails. /// if is a , otherwise. - static bool CheckSupportsType(Type type, bool validate) + static bool CheckSupportsType(Type? type, bool validate) { ArgumentNullException.ThrowIfNull(type); @@ -35,7 +33,7 @@ static bool CheckSupportsType(Type type, bool validate) } /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter? writer, object? value, JsonSerializer serializer) { ArgumentNullException.ThrowIfNull(writer); @@ -54,7 +52,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s } /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader? reader, Type? objectType, object? existingValue, JsonSerializer serializer) { ArgumentNullException.ThrowIfNull(reader); @@ -67,7 +65,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist { try { - var v = global::System.Version.Parse((string)reader.Value); + var v = global::System.Version.Parse((string)reader.Value!); return v.Semver(); } catch (Exception ex) @@ -90,7 +88,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist public object ReadYaml(IParser parser, Type type) => throw new NotSupportedException("Deserialization not supported!"); // The default implementation is fine at handling this /// - public void WriteYaml(IEmitter emitter, object value, Type type) + public void WriteYaml(IEmitter? emitter, object? value, Type type) { ArgumentNullException.ThrowIfNull(emitter); From a9a82f0beeb3f03189aad0221678ea6f672dc0c2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:23:44 -0500 Subject: [PATCH 303/717] Nullify `ApplicationBuilderExtensions` --- .../Extensions/ApplicationBuilderExtensions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/ApplicationBuilderExtensions.cs b/src/Tgstation.Server.Host/Extensions/ApplicationBuilderExtensions.cs index 1e69a743f0b..637484f5bd1 100644 --- a/src/Tgstation.Server.Host/Extensions/ApplicationBuilderExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ApplicationBuilderExtensions.cs @@ -17,8 +17,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// From a4e1b8ea7696dc96c3a6b34e45f5c1d6845400fd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:24:11 -0500 Subject: [PATCH 304/717] Nullify `ChatChannelExtensions` --- src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs b/src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs index e4bb8948e3e..3b77bd0b1f3 100644 --- a/src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// @@ -25,7 +23,7 @@ static class ChatChannelExtensions /// /// The to retrieve information from. /// The IRC channel key stored in the if it exists, otherwise. - public static string GetIrcChannelKey(this ChatChannel chatChannel) + public static string? GetIrcChannelKey(this ChatChannel chatChannel) { var splits = GetIrcChannelSplits(chatChannel); if (splits.Count < 2) From 79b188a07f9ae9f3df44e2a304c0745f42b612f3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:24:30 -0500 Subject: [PATCH 305/717] Nullify `ControllerBaseExtensions` --- .../Extensions/ControllerBaseExtensions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs b/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs index 73f87308c7a..9ab3b1cc87e 100644 --- a/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// From cd9f07b4970e87a565f8bb87f419891df73f74fe Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:25:00 -0500 Subject: [PATCH 306/717] Nullify `DatabaseCollectionExtensions` --- .../Extensions/DatabaseCollectionExtensions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/DatabaseCollectionExtensions.cs b/src/Tgstation.Server.Host/Extensions/DatabaseCollectionExtensions.cs index 40f005609c9..ea50a7af172 100644 --- a/src/Tgstation.Server.Host/Extensions/DatabaseCollectionExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/DatabaseCollectionExtensions.cs @@ -9,8 +9,6 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// From 6a53712175bdf90989613656eb918c951a9e3f2e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:25:19 -0500 Subject: [PATCH 307/717] Nullify `DateTimeOffsetExtensions` --- .../Extensions/DateTimeOffsetExtensions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/DateTimeOffsetExtensions.cs b/src/Tgstation.Server.Host/Extensions/DateTimeOffsetExtensions.cs index 1d3a864cf96..44b0669314f 100644 --- a/src/Tgstation.Server.Host/Extensions/DateTimeOffsetExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/DateTimeOffsetExtensions.cs @@ -1,8 +1,6 @@ using System; using System.Globalization; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// From 33e7d6c3afa89bc5103cfe6e0d4b02091bbe3b21 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:26:10 -0500 Subject: [PATCH 308/717] Nullify `FileTransferStreamHandlerExtensions` --- .../Extensions/FileTransferStreamHandlerExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/FileTransferStreamHandlerExtensions.cs b/src/Tgstation.Server.Host/Extensions/FileTransferStreamHandlerExtensions.cs index 632bd0bd722..5bae10e79bd 100644 --- a/src/Tgstation.Server.Host/Extensions/FileTransferStreamHandlerExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/FileTransferStreamHandlerExtensions.cs @@ -14,8 +14,6 @@ using Tgstation.Server.Host.Controllers.Results; using Tgstation.Server.Host.Transfer; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// @@ -69,7 +67,9 @@ public static async ValueTask GenerateDownloadResponse( } catch { - await stream.DisposeAsync(); + if (stream != null) + await stream.DisposeAsync(); + throw; } } From 5415d7c4abaae7d5d2e6808b6f9c43ca3856f6f6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:26:26 -0500 Subject: [PATCH 309/717] Nullify `GeneralConfigurationExtensions` --- .../Extensions/GeneralConfigurationExtensions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/GeneralConfigurationExtensions.cs b/src/Tgstation.Server.Host/Extensions/GeneralConfigurationExtensions.cs index 5214ed0085f..0a2a5fc8d84 100644 --- a/src/Tgstation.Server.Host/Extensions/GeneralConfigurationExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/GeneralConfigurationExtensions.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// From f2a12cbb8220098f58098214d40d76e716088923 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:26:39 -0500 Subject: [PATCH 310/717] Nullify `HostBuilderExtensions` --- src/Tgstation.Server.Host/Extensions/HostBuilderExtensions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/HostBuilderExtensions.cs b/src/Tgstation.Server.Host/Extensions/HostBuilderExtensions.cs index 160293e7442..6bfc4cb528f 100644 --- a/src/Tgstation.Server.Host/Extensions/HostBuilderExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/HostBuilderExtensions.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Host.Setup; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// From e4de050af6c86a947c1cdbe12b6e72bc874c77ea Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:26:50 -0500 Subject: [PATCH 311/717] Nullify `ModelBuilderExtensions` --- src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs b/src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs index 8ecf17c6006..f503f2c7179 100644 --- a/src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Api.Models; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// From 7abcce481900445d88e5674015ce81bc4e28cbdb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:27:38 -0500 Subject: [PATCH 312/717] Nullify `ModelBuilderExtensions` --- .../Extensions/ModelBuilderExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs b/src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs index f503f2c7179..0db51009526 100644 --- a/src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ModelBuilderExtensions.cs @@ -23,7 +23,7 @@ static class ModelBuilderExtensions /// . public static ModelBuilder MapMySqlTextField( this ModelBuilder modelBuilder, - Expression> expression) + Expression> expression) where TEntity : class { var property = modelBuilder @@ -47,7 +47,7 @@ public static ModelBuilder MapMySqlTextField( /// The entity. /// The accessing the relevant property. /// The pointed to by . - static PropertyInfo GetPropertyFromExpression(Expression> expression) + static PropertyInfo GetPropertyFromExpression(Expression> expression) { MemberExpression memberExpression; From f54eac33cae158e9cebd9b35e6c043734caffe2b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:28:06 -0500 Subject: [PATCH 313/717] Nullify `ResultExtensions` --- src/Tgstation.Server.Host/Extensions/ResultExtensions.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/ResultExtensions.cs b/src/Tgstation.Server.Host/Extensions/ResultExtensions.cs index 4f7d3bc4a4a..f1157f22866 100644 --- a/src/Tgstation.Server.Host/Extensions/ResultExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ResultExtensions.cs @@ -7,8 +7,6 @@ using Remora.Rest.Results; using Remora.Results; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// @@ -118,7 +116,7 @@ static void FormatErrorDetails(IPropertyErrorDetails propertyErrorDetails, Strin /// /// The of . /// The to mutate. - static void FormatErrorDetails(IEnumerable errorDetails, StringBuilder stringBuilder) + static void FormatErrorDetails(IEnumerable? errorDetails, StringBuilder stringBuilder) { if (errorDetails == null) return; From d23a4efca0fb85a785a2ed90d51c1491fa41ae1f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:31:17 -0500 Subject: [PATCH 314/717] Nullify `ServiceCollectionExtensions` --- .../Extensions/ServiceCollectionExtensions.cs | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs b/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs index f32d2a675d1..cc7eb227a93 100644 --- a/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ServiceCollectionExtensions.cs @@ -18,8 +18,6 @@ using Tgstation.Server.Host.Utils.GitHub; using Tgstation.Server.Host.Utils.SignalR; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// @@ -30,22 +28,22 @@ static class ServiceCollectionExtensions /// /// The implementation used in calls to . /// - static Type chatProviderFactoryType; + static Type? chatProviderFactoryType; /// /// The implementation used in calls to . /// - static Type gitHubServiceFactoryType; + static Type? gitHubServiceFactoryType; /// /// The implementation used in calls to . /// - static Type fileDownloaderType; + static Type? fileDownloaderType; /// /// A for an additional to use. /// - static ServiceDescriptor additionalLoggerProvider; + static ServiceDescriptor? additionalLoggerProvider; /// /// Initializes static members of the class. @@ -94,7 +92,7 @@ public static IServiceCollection AddFileDownloader(this IServiceCollection servi { ArgumentNullException.ThrowIfNull(serviceCollection); - serviceCollection.AddSingleton(typeof(IFileDownloader), fileDownloaderType); + serviceCollection.AddSingleton(typeof(IFileDownloader), fileDownloaderType ?? throw new InvalidOperationException("fileDownloaderType not set!")); return serviceCollection; } @@ -109,7 +107,7 @@ public static IServiceCollection AddGitHub(this IServiceCollection serviceCollec ArgumentNullException.ThrowIfNull(serviceCollection); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(typeof(IGitHubServiceFactory), gitHubServiceFactoryType); + serviceCollection.AddSingleton(typeof(IGitHubServiceFactory), gitHubServiceFactoryType ?? throw new InvalidOperationException("gitHubServiceFactoryType not set!")); return serviceCollection; } @@ -135,7 +133,7 @@ public static IServiceCollection AddChatProviderFactory(this IServiceCollection { ArgumentNullException.ThrowIfNull(serviceCollection); - return serviceCollection.AddSingleton(typeof(IProviderFactory), chatProviderFactoryType); + return serviceCollection.AddSingleton(typeof(IProviderFactory), chatProviderFactoryType ?? throw new InvalidOperationException("chatProviderFactoryType not set!")); } /// @@ -160,7 +158,7 @@ public static IServiceCollection UseStandardConfig(this IServiceCollect if (sectionField.FieldType != stringType) throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "{0} has invalid {1} field type, must be {2}!", configType, SectionFieldName, stringType)); - var sectionName = (string)sectionField.GetValue(null); + var sectionName = (string)sectionField.GetValue(null)!; return serviceCollection.Configure(configuration.GetSection(sectionName)); } @@ -178,10 +176,10 @@ public static IServiceCollection UseStandardConfig(this IServiceCollect public static IServiceCollection SetupLogging( this IServiceCollection serviceCollection, Action configurationAction, - Action sinkConfigurationAction = null, - ElasticsearchSinkOptions elasticsearchSinkOptions = null, - InternalConfiguration internalConfiguration = null, - FileLoggingConfiguration fileLoggingConfiguration = null) + Action? sinkConfigurationAction = null, + ElasticsearchSinkOptions? elasticsearchSinkOptions = null, + InternalConfiguration? internalConfiguration = null, + FileLoggingConfiguration? fileLoggingConfiguration = null) { if (internalConfiguration != null) ArgumentNullException.ThrowIfNull(fileLoggingConfiguration); @@ -205,7 +203,7 @@ public static IServiceCollection SetupLogging( + SerilogContextHelper.Template + "){NewLine} {Message:lj}{NewLine}{Exception}"; - if (!((internalConfiguration?.UsingSystemD ?? false) && !fileLoggingConfiguration.Disable)) + if (!((internalConfiguration?.UsingSystemD ?? false) && !(fileLoggingConfiguration?.Disable ?? false))) sinkConfiguration.Console(outputTemplate: template, formatProvider: CultureInfo.InvariantCulture); sinkConfigurationAction?.Invoke(sinkConfiguration); }); From 98b5fdcff53024425e6e8222b18ba9be53831793 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:31:31 -0500 Subject: [PATCH 315/717] Nullify `SocketExtensions` --- src/Tgstation.Server.Host/Extensions/SocketExtensions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs index 1c74a95a500..6c1a695025e 100644 --- a/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/SocketExtensions.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// From 437d837ca41029fff5b83c89f5acfd8e47158aaa Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:32:39 -0500 Subject: [PATCH 316/717] Nullify `TaskExtensions` --- src/Tgstation.Server.Host/Extensions/TaskExtensions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs b/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs index b2e5eaaf9e5..55b6701dbbf 100644 --- a/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// From e3a7570574e6f3cda5995ad3d1b0c4d3d3b5083f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 21:33:14 -0500 Subject: [PATCH 317/717] Nullify `WebHostBuilderExtensions` --- .../Extensions/WebHostBuilderExtensions.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Extensions/WebHostBuilderExtensions.cs b/src/Tgstation.Server.Host/Extensions/WebHostBuilderExtensions.cs index c2f430e1723..e6815cd7a0f 100644 --- a/src/Tgstation.Server.Host/Extensions/WebHostBuilderExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/WebHostBuilderExtensions.cs @@ -13,8 +13,6 @@ using Tgstation.Server.Host.Setup; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Extensions { /// From 800b772736562a77972f18751ba767d92ff680a8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 24 Nov 2023 09:32:52 -0500 Subject: [PATCH 318/717] Nullify `AuthenticationContext` --- .../Security/AuthenticationContext.cs | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContext.cs b/src/Tgstation.Server.Host/Security/AuthenticationContext.cs index b8719d5cc84..f0f4e5be037 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContext.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContext.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Api.Rights; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Security { /// @@ -15,16 +13,26 @@ sealed class AuthenticationContext : IAuthenticationContext, IDisposable public bool Valid { get; private set; } /// - public User User { get; private set; } + public User User => user ?? throw new InvalidOperationException("AuthenticationContext is invalid!"); /// - public PermissionSet PermissionSet { get; private set; } + public PermissionSet PermissionSet => permissionSet ?? throw new InvalidOperationException("AuthenticationContext is invalid!"); /// - public InstancePermissionSet InstancePermissionSet { get; private set; } + public InstancePermissionSet? InstancePermissionSet { get; private set; } /// - public ISystemIdentity SystemIdentity { get; private set; } + public ISystemIdentity? SystemIdentity { get; private set; } + + /// + /// Backing field for . + /// + User? user; + + /// + /// Backing field for . + /// + PermissionSet? permissionSet; /// /// Initializes a new instance of the class. @@ -44,10 +52,10 @@ public AuthenticationContext() /// The value of . public void Initialize(ISystemIdentity systemIdentity, User user, InstancePermissionSet instanceUser) { - User = user ?? throw new ArgumentNullException(nameof(user)); + this.user = user ?? throw new ArgumentNullException(nameof(user)); if (systemIdentity == null && User.SystemIdentifier != null) throw new ArgumentNullException(nameof(systemIdentity)); - PermissionSet = user.PermissionSet + permissionSet = user.PermissionSet ?? user.Group.PermissionSet ?? throw new ArgumentException("No PermissionSet provider", nameof(user)); InstancePermissionSet = instanceUser; @@ -74,9 +82,9 @@ public ulong GetRight(RightsType rightsType) var nullableType = typeof(Nullable<>); var nullableRightsType = nullableType.MakeGenericType(rightsEnum); - var prop = typeToCheck.GetProperties().Where(x => x.PropertyType == nullableRightsType).First(); + var prop = typeToCheck.GetProperties().Where(x => x.PropertyType == nullableRightsType && x.CanRead).First(); - var right = prop.GetMethod.Invoke( + var right = prop.GetMethod!.Invoke( isInstance ? InstancePermissionSet : PermissionSet, From 754e4a4c3bbe385eef610472821114f7ea2bc22a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 24 Nov 2023 09:33:29 -0500 Subject: [PATCH 319/717] Nullify `AuthenticationContextAuthorizationFilter` --- .../Security/AuthenticationContextAuthorizationFilter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContextAuthorizationFilter.cs b/src/Tgstation.Server.Host/Security/AuthenticationContextAuthorizationFilter.cs index a3191770e46..b009f599ada 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContextAuthorizationFilter.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContextAuthorizationFilter.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; -#nullable disable +using Tgstation.Server.Host.Models; namespace Tgstation.Server.Host.Security { @@ -45,7 +45,7 @@ public void OnAuthorization(AuthorizationFilterContext context) return; } - if (authenticationContext.User.Enabled.Value) + if (authenticationContext.User.Require(x => x.Enabled)) return; logger.LogTrace("authenticationContext is for a disabled user!"); From a982471e2408ece9560125484d64097af8c220d4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 24 Nov 2023 09:33:59 -0500 Subject: [PATCH 320/717] Nullify `AuthenticationContextClaimsTransformation` --- .../Security/AuthenticationContextClaimsTransformation.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContextClaimsTransformation.cs b/src/Tgstation.Server.Host/Security/AuthenticationContextClaimsTransformation.cs index 9cf5de9de75..c5b1fe0ce22 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContextClaimsTransformation.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContextClaimsTransformation.cs @@ -13,8 +13,6 @@ using Tgstation.Server.Api.Rights; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Security { /// @@ -30,7 +28,7 @@ sealed class AuthenticationContextClaimsTransformation : IClaimsTransformation /// /// The for the . /// - readonly ApiHeaders apiHeaders; + readonly ApiHeaders? apiHeaders; /// /// Initializes a new instance of the class. From c269fbd57c76efb33d1fcb93eac06b327fb016ee Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 24 Nov 2023 09:35:04 -0500 Subject: [PATCH 321/717] Nullify `AuthenticationContextFactory` --- src/Tgstation.Server.Host/Security/AuthenticationContext.cs | 2 +- .../Security/AuthenticationContextFactory.cs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContext.cs b/src/Tgstation.Server.Host/Security/AuthenticationContext.cs index f0f4e5be037..c40d122743e 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContext.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContext.cs @@ -50,7 +50,7 @@ public AuthenticationContext() /// The value of . /// The value of . /// The value of . - public void Initialize(ISystemIdentity systemIdentity, User user, InstancePermissionSet instanceUser) + public void Initialize(ISystemIdentity? systemIdentity, User user, InstancePermissionSet? instanceUser) { this.user = user ?? throw new ArgumentNullException(nameof(user)); if (systemIdentity == null && User.SystemIdentifier != null) diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs b/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs index 3be3bc8061c..8dca0248c77 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs @@ -11,8 +11,6 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Security { /// @@ -99,7 +97,7 @@ public async ValueTask CreateAuthenticationContext(long return currentAuthenticationContext; } - ISystemIdentity systemIdentity; + ISystemIdentity? systemIdentity; if (user.SystemIdentifier != null) systemIdentity = identityCache.LoadCachedIdentity(user); else @@ -116,7 +114,7 @@ public async ValueTask CreateAuthenticationContext(long var userPermissionSet = user.PermissionSet ?? user.Group.PermissionSet; try { - InstancePermissionSet instancePermissionSet = null; + InstancePermissionSet? instancePermissionSet = null; if (instanceId.HasValue) { instancePermissionSet = await databaseContext.InstancePermissionSets From 760bc8b29a5c9e6ecf3dc31008b03ae709f81da7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 24 Nov 2023 09:36:47 -0500 Subject: [PATCH 322/717] Nullify `AuthorizationContextHubFilter` --- .../Security/AuthorizationContextHubFilter.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/AuthorizationContextHubFilter.cs b/src/Tgstation.Server.Host/Security/AuthorizationContextHubFilter.cs index a64f3d4cdbd..3eefac4f2ea 100644 --- a/src/Tgstation.Server.Host/Security/AuthorizationContextHubFilter.cs +++ b/src/Tgstation.Server.Host/Security/AuthorizationContextHubFilter.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; -#nullable disable +using Tgstation.Server.Host.Models; namespace Tgstation.Server.Host.Security { @@ -46,7 +46,7 @@ public async Task OnConnectedAsync(HubLifetimeContext context, Func - public async ValueTask InvokeMethodAsync(HubInvocationContext invocationContext, Func> next) + public async ValueTask InvokeMethodAsync(HubInvocationContext invocationContext, Func> next) { ArgumentNullException.ThrowIfNull(invocationContext); if (ValidateAuthenticationContext(invocationContext.Hub)) @@ -64,7 +64,7 @@ bool ValidateAuthenticationContext(Hub hub) { if (!authenticationContext.Valid) logger.LogTrace("The token for connection {connectionId} is no longer authenticated! Aborting...", hub.Context.ConnectionId); - else if (!authenticationContext.User.Enabled.Value) + else if (!authenticationContext.User.Require(x => x.Enabled)) logger.LogTrace("The token for connection {connectionId} is no longer authorized! Aborting...", hub.Context.ConnectionId); else return true; @@ -75,8 +75,8 @@ bool ValidateAuthenticationContext(Hub hub) prop => prop.PropertyType.IsConstructedGenericType && prop.Name == nameof(hub.Clients)); var clients = typedClientsProperty.GetValue(hub); - var callerProperty = clients.GetType().GetProperty(nameof(hub.Clients.Caller)); - var caller = callerProperty.GetValue(clients); + var callerProperty = clients!.GetType().GetProperty(nameof(hub.Clients.Caller)); + var caller = callerProperty!.GetValue(clients); hub.Context.Abort(); return false; From fd03e349a54ba061772fe39f5380db629507846c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 24 Nov 2023 09:49:35 -0500 Subject: [PATCH 323/717] Nullify `CryptographySuite` --- src/Tgstation.Server.Host/Security/CryptographySuite.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/CryptographySuite.cs b/src/Tgstation.Server.Host/Security/CryptographySuite.cs index 8d2f6eeca52..d98e61c303f 100644 --- a/src/Tgstation.Server.Host/Security/CryptographySuite.cs +++ b/src/Tgstation.Server.Host/Security/CryptographySuite.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Security { /// From 74d53e04977884be273bf1c89cf63b0ef73fac4f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 24 Nov 2023 09:50:11 -0500 Subject: [PATCH 324/717] Nullify `IAuthenticationContext` --- .../Security/IAuthenticationContext.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/IAuthenticationContext.cs b/src/Tgstation.Server.Host/Security/IAuthenticationContext.cs index 39da97b00e3..8277a6601d2 100644 --- a/src/Tgstation.Server.Host/Security/IAuthenticationContext.cs +++ b/src/Tgstation.Server.Host/Security/IAuthenticationContext.cs @@ -1,8 +1,6 @@ using Tgstation.Server.Api.Rights; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Security { /// @@ -28,7 +26,7 @@ public interface IAuthenticationContext /// /// The 's effective if applicable. /// - InstancePermissionSet InstancePermissionSet { get; } + InstancePermissionSet? InstancePermissionSet { get; } /// /// Get the value of a given . @@ -40,6 +38,6 @@ public interface IAuthenticationContext /// /// The of if applicable. /// - ISystemIdentity SystemIdentity { get; } + ISystemIdentity? SystemIdentity { get; } } } From ef750acbba22f6c4fce62cb3800f1e8641b4a079 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 09:34:59 -0500 Subject: [PATCH 325/717] Nullify `IAuthenticationContextFactory` --- .../Security/IAuthenticationContextFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/IAuthenticationContextFactory.cs b/src/Tgstation.Server.Host/Security/IAuthenticationContextFactory.cs index 945b4e09add..cb70a50b18e 100644 --- a/src/Tgstation.Server.Host/Security/IAuthenticationContextFactory.cs +++ b/src/Tgstation.Server.Host/Security/IAuthenticationContextFactory.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Security { /// From 6046f0e635050266cc0b44d6abc4c56ea5c46dd2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 09:35:38 -0500 Subject: [PATCH 326/717] Nullify `ICryptographySuite` --- src/Tgstation.Server.Host/Security/ICryptographySuite.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/ICryptographySuite.cs b/src/Tgstation.Server.Host/Security/ICryptographySuite.cs index 955fdac6ae4..257a78f4d19 100644 --- a/src/Tgstation.Server.Host/Security/ICryptographySuite.cs +++ b/src/Tgstation.Server.Host/Security/ICryptographySuite.cs @@ -1,7 +1,5 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Security { /// From 616251e5a19276f9ef2c7e855962c3e72fca36dc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 09:37:42 -0500 Subject: [PATCH 327/717] Nullify `IdentityCache` --- .../Security/IdentityCache.cs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/IdentityCache.cs b/src/Tgstation.Server.Host/Security/IdentityCache.cs index 6c2a98b2009..c42ffab3f67 100644 --- a/src/Tgstation.Server.Host/Security/IdentityCache.cs +++ b/src/Tgstation.Server.Host/Security/IdentityCache.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Security { /// @@ -56,12 +54,14 @@ public void CacheSystemIdentity(User user, ISystemIdentity systemIdentity, DateT ArgumentNullException.ThrowIfNull(user); ArgumentNullException.ThrowIfNull(systemIdentity); + var uid = user.Require(x => x.Id); + var sysId = systemIdentity.Uid; + lock (cachedIdentities) { - var uid = systemIdentity.Uid; - logger.LogDebug("Caching system identity {0} of user {1}", uid, user.Id); + logger.LogDebug("Caching system identity {sysId} of user {uid}", sysId, uid); - if (cachedIdentities.TryGetValue(user.Id.Value, out var identCache)) + if (cachedIdentities.TryGetValue(uid, out var identCache)) { logger.LogTrace("Expiring previously cached identity..."); identCache.Dispose(); // also clears it out @@ -72,12 +72,12 @@ public void CacheSystemIdentity(User user, ISystemIdentity systemIdentity, DateT asyncDelayer, () => { - logger.LogDebug("Expiring system identity cache for user {0}", user.Id); + logger.LogDebug("Expiring system identity cache for user {uid}", uid); lock (cachedIdentities) - cachedIdentities.Remove(user.Id.Value); + cachedIdentities.Remove(uid); }, expiry); - cachedIdentities.Add(user.Id.Value, identCache); + cachedIdentities.Add(uid, identCache); } } @@ -85,9 +85,11 @@ public void CacheSystemIdentity(User user, ISystemIdentity systemIdentity, DateT public ISystemIdentity LoadCachedIdentity(User user) { ArgumentNullException.ThrowIfNull(user); + var uid = user.Require(x => x.Id); lock (cachedIdentities) - if (cachedIdentities.TryGetValue(user.Id.Value, out var identity)) + if (cachedIdentities.TryGetValue(uid, out var identity)) return identity.SystemIdentity.Clone(); + throw new InvalidOperationException("Cached system identity has expired!"); } } From 2302c48ea1f42b9b72f640412202f213d148fee5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 09:39:57 -0500 Subject: [PATCH 328/717] Nullify `IdentityCacheObject` --- src/Tgstation.Server.Host/Security/IdentityCacheObject.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs b/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs index d7125b877fe..7cc10664e5a 100644 --- a/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs +++ b/src/Tgstation.Server.Host/Security/IdentityCacheObject.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Security { /// From 4569c8cb201caabf89ef9a8db3fa51e226cd28d9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 09:42:06 -0500 Subject: [PATCH 329/717] Nullify `IIdentityCache` --- src/Tgstation.Server.Host/Security/IIdentityCache.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/IIdentityCache.cs b/src/Tgstation.Server.Host/Security/IIdentityCache.cs index 64fd3f39a97..75010f2c644 100644 --- a/src/Tgstation.Server.Host/Security/IIdentityCache.cs +++ b/src/Tgstation.Server.Host/Security/IIdentityCache.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Security { /// @@ -23,7 +21,7 @@ public interface IIdentityCache /// Attempt to load a cached . /// /// The the belongs to. - /// The cached or if it doesn't exist or expired. + /// The cached . ISystemIdentity LoadCachedIdentity(User user); } } From 739d0778b766a51ffa59afa9a1f5c8c0f1d051ee Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 09:53:19 -0500 Subject: [PATCH 330/717] Nullify `IPermissionsUpdateNotifyee` --- .../Security/IPermissionsUpdateNotifyee.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/IPermissionsUpdateNotifyee.cs b/src/Tgstation.Server.Host/Security/IPermissionsUpdateNotifyee.cs index dd313adc86e..7a95f7f0760 100644 --- a/src/Tgstation.Server.Host/Security/IPermissionsUpdateNotifyee.cs +++ b/src/Tgstation.Server.Host/Security/IPermissionsUpdateNotifyee.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Security { /// From 12d0c19794066ecdf3ec7114f10efa93469bb55a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 11:11:12 -0500 Subject: [PATCH 331/717] Fix debugging issue with host watchdogs --- src/Tgstation.Server.Host.Watchdog/Watchdog.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index a574a6ab6b1..4813383440d 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -101,7 +101,10 @@ public async ValueTask RunAsync(bool runConfigure, string[] args, Cancella Directory.Delete(assemblyStoragePath, true); Directory.CreateDirectory(defaultAssemblyPath); - var sourcePath = "../../../../Tgstation.Server.Host/bin/Debug/net8.0"; + var sourcePath = Path.GetFullPath( + Path.Combine( + rootLocation, + "../../../../Tgstation.Server.Host/bin/Debug/net8.0")); foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories)) Directory.CreateDirectory(dirPath.Replace(sourcePath, defaultAssemblyPath, StringComparison.Ordinal)); From c4ce4dad542993444230e15d9eab806b69c88bbc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 12:20:42 -0500 Subject: [PATCH 332/717] Fix deadlock in `ServiceLifetime` --- .../ServiceLifetime.cs | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host.Service/ServiceLifetime.cs b/src/Tgstation.Server.Host.Service/ServiceLifetime.cs index efc058fbaab..f29cd0e9192 100644 --- a/src/Tgstation.Server.Host.Service/ServiceLifetime.cs +++ b/src/Tgstation.Server.Host.Service/ServiceLifetime.cs @@ -152,14 +152,24 @@ async Task RunWatchdog(Action stopService, IWatchdog watchdog, string[] args, Ca await localWatchdogTask; - try - { - stopService(); - } - catch (Exception ex) + async void StopServiceAsync() { - logger.LogError(ex, "Error stopping service!"); + try + { + // This can call OnStop which waits on this task to complete, must be threaded off or it will deadlock + await Task.Run(stopService, cancellationToken); + } + catch (OperationCanceledException ex) + { + logger.LogDebug(ex, "Stopping service cancelled!"); + } + catch (Exception ex) + { + logger.LogError(ex, "Error stopping service!"); + } } + + StopServiceAsync(); } /// From 18a378f0e5192285796896ddf5f5547468c8311c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 12:31:42 -0500 Subject: [PATCH 333/717] Nullify `ISystemIdentity` --- src/Tgstation.Server.Host/Security/ISystemIdentity.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/ISystemIdentity.cs b/src/Tgstation.Server.Host/Security/ISystemIdentity.cs index e865b0345b2..bd63d784dea 100644 --- a/src/Tgstation.Server.Host/Security/ISystemIdentity.cs +++ b/src/Tgstation.Server.Host/Security/ISystemIdentity.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Security { /// From b6b83ce5f0ff24db5c1d5a84a4dd95e4daeb8103 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 12:33:14 -0500 Subject: [PATCH 334/717] Nullify `ISystemIdentityFactory` --- .../Security/ISystemIdentityFactory.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs b/src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs index de6e58d431e..604ad60d8a9 100644 --- a/src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs +++ b/src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Security { /// @@ -32,7 +30,7 @@ public interface ISystemIdentityFactory /// The username of the user. /// The password of the user. /// The for the operation. - /// A resulting in a new based on the given credentials. - Task CreateSystemIdentity(string username, string password, CancellationToken cancellationToken); + /// A resulting in a new based on the given credentials on success, on failure. + Task CreateSystemIdentity(string username, string password, CancellationToken cancellationToken); } } From 17087376152b50337623d992df856b69c6a913ea Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 12:33:57 -0500 Subject: [PATCH 335/717] Nullify `ITokenFactory` --- src/Tgstation.Server.Host/Security/ITokenFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/ITokenFactory.cs b/src/Tgstation.Server.Host/Security/ITokenFactory.cs index 107965394c6..bf9a70fab15 100644 --- a/src/Tgstation.Server.Host/Security/ITokenFactory.cs +++ b/src/Tgstation.Server.Host/Security/ITokenFactory.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Security { /// From d8ae12ce110982b82e381e5d2e4afb063e8949d9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 12:52:14 -0500 Subject: [PATCH 336/717] Nullify `PosixSystemIdentity` --- src/Tgstation.Server.Host/Security/PosixSystemIdentity.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/PosixSystemIdentity.cs b/src/Tgstation.Server.Host/Security/PosixSystemIdentity.cs index 4f978e76d14..67f0e3ac838 100644 --- a/src/Tgstation.Server.Host/Security/PosixSystemIdentity.cs +++ b/src/Tgstation.Server.Host/Security/PosixSystemIdentity.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Security { /// From bb76339461b0ff37d26e2fe98606511338134a2e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 12:54:27 -0500 Subject: [PATCH 337/717] Nullify `PosixSystemIdentityFactory` --- .../Security/PosixSystemIdentityFactory.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/PosixSystemIdentityFactory.cs b/src/Tgstation.Server.Host/Security/PosixSystemIdentityFactory.cs index 876cca613e4..ae1cf2c0369 100644 --- a/src/Tgstation.Server.Host/Security/PosixSystemIdentityFactory.cs +++ b/src/Tgstation.Server.Host/Security/PosixSystemIdentityFactory.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Security { /// @@ -21,6 +19,6 @@ sealed class PosixSystemIdentityFactory : ISystemIdentityFactory public Task CreateSystemIdentity(User user, CancellationToken cancellationToken) => throw new NotImplementedException(); /// - public Task CreateSystemIdentity(string username, string password, CancellationToken cancellationToken) => throw new NotImplementedException(); + public Task CreateSystemIdentity(string username, string password, CancellationToken cancellationToken) => throw new NotImplementedException(); } } From 9b05ce3b9caf811f09faa6b753ef6e22be265f83 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 12:55:19 -0500 Subject: [PATCH 338/717] Nullify `TgsAuthorizeAttribute` --- src/Tgstation.Server.Host/Security/TgsAuthorizeAttribute.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/TgsAuthorizeAttribute.cs b/src/Tgstation.Server.Host/Security/TgsAuthorizeAttribute.cs index a80205bb6e1..0fc4c11c1a0 100644 --- a/src/Tgstation.Server.Host/Security/TgsAuthorizeAttribute.cs +++ b/src/Tgstation.Server.Host/Security/TgsAuthorizeAttribute.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Api.Rights; -#nullable disable - namespace Tgstation.Server.Host.Security { /// From e1b511386ddc2268232b5f946f7fdb09e154a8d1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 12:56:34 -0500 Subject: [PATCH 339/717] Nullfiy `TokenFactory` --- src/Tgstation.Server.Host/Security/TokenFactory.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/TokenFactory.cs b/src/Tgstation.Server.Host/Security/TokenFactory.cs index 3a17f2ac865..fcc5990c2f1 100644 --- a/src/Tgstation.Server.Host/Security/TokenFactory.cs +++ b/src/Tgstation.Server.Host/Security/TokenFactory.cs @@ -10,10 +10,9 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Host.Configuration; +using Tgstation.Server.Host.Models; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Security { /// @@ -84,10 +83,11 @@ public TokenFactory( } /// - public TokenResponse CreateToken(Models.User user, bool oAuth) + public TokenResponse CreateToken(User user, bool oAuth) { ArgumentNullException.ThrowIfNull(user); + var uid = user.Require(x => x.Id); var now = DateTimeOffset.UtcNow; var nowUnix = now.ToUnixTimeSeconds(); @@ -115,7 +115,7 @@ public TokenResponse CreateToken(Models.User user, bool oAuth) Enumerable.Empty(), new Dictionary { - { JwtRegisteredClaimNames.Sub, user.Id.Value.ToString(CultureInfo.InvariantCulture) }, + { JwtRegisteredClaimNames.Sub, uid.ToString(CultureInfo.InvariantCulture) }, }, notBefore.UtcDateTime, expiry.UtcDateTime, From 7b32abc0a24ffe3b0e59af34a1f560a5004715e4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 13:11:18 -0500 Subject: [PATCH 340/717] Nullify `WindowsSystemIdentity` --- .../Security/WindowsSystemIdentity.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/WindowsSystemIdentity.cs b/src/Tgstation.Server.Host/Security/WindowsSystemIdentity.cs index f4ac20da190..e15b51557d5 100644 --- a/src/Tgstation.Server.Host/Security/WindowsSystemIdentity.cs +++ b/src/Tgstation.Server.Host/Security/WindowsSystemIdentity.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Security { /// @@ -18,10 +16,10 @@ namespace Tgstation.Server.Host.Security sealed class WindowsSystemIdentity : ISystemIdentity { /// - public string Uid => (userPrincipal?.Sid ?? identity.User).ToString(); + public string Uid => (userPrincipal?.Sid ?? identity!.User!).ToString(); // we kno user isn't null because it can only be the case when anonymous (checked in this constructor) /// - public string Username => userPrincipal?.Name ?? identity.Name; + public string Username => userPrincipal?.Name ?? identity!.Name; /// public bool CanCreateSymlinks => canCreateSymlinks ?? throw new NotSupportedException(); @@ -29,12 +27,12 @@ sealed class WindowsSystemIdentity : ISystemIdentity /// /// The for the . /// - readonly WindowsIdentity identity; + readonly WindowsIdentity? identity; /// /// The for the . /// - readonly UserPrincipal userPrincipal; + readonly UserPrincipal? userPrincipal; /// /// Backing field for . @@ -48,6 +46,9 @@ sealed class WindowsSystemIdentity : ISystemIdentity public WindowsSystemIdentity(WindowsIdentity identity) { this.identity = identity ?? throw new ArgumentNullException(nameof(identity)); + if (identity.IsAnonymous) + throw new InvalidOperationException($"Cannot use anonymous {nameof(WindowsIdentity)} as a {nameof(WindowsSystemIdentity)}!"); + canCreateSymlinks = new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator); } @@ -67,7 +68,7 @@ public void Dispose() identity.Dispose(); else { - var context = userPrincipal.Context; + var context = userPrincipal!.Context; userPrincipal.Dispose(); context.Dispose(); } From 19ad5e71d729fae8f7dcba80015a63d9d8d15377 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 13:15:50 -0500 Subject: [PATCH 341/717] Nullify `WindowsSystemIdentityFactory` --- .../Security/ISystemIdentityFactory.cs | 2 +- .../Security/PosixSystemIdentityFactory.cs | 2 +- .../Security/WindowsSystemIdentityFactory.cs | 18 ++++++++---------- .../System/NativeMethods.cs | 2 +- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs b/src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs index 604ad60d8a9..e2e245e38e2 100644 --- a/src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs +++ b/src/Tgstation.Server.Host/Security/ISystemIdentityFactory.cs @@ -22,7 +22,7 @@ public interface ISystemIdentityFactory /// The user to create a for. /// The for the operation. /// A resulting in a new based on the given or if the has no . - Task CreateSystemIdentity(User user, CancellationToken cancellationToken); + Task CreateSystemIdentity(User user, CancellationToken cancellationToken); /// /// Create a for a given username and password. diff --git a/src/Tgstation.Server.Host/Security/PosixSystemIdentityFactory.cs b/src/Tgstation.Server.Host/Security/PosixSystemIdentityFactory.cs index ae1cf2c0369..062a42747f3 100644 --- a/src/Tgstation.Server.Host/Security/PosixSystemIdentityFactory.cs +++ b/src/Tgstation.Server.Host/Security/PosixSystemIdentityFactory.cs @@ -16,7 +16,7 @@ sealed class PosixSystemIdentityFactory : ISystemIdentityFactory public ISystemIdentity GetCurrent() => new PosixSystemIdentity(); /// - public Task CreateSystemIdentity(User user, CancellationToken cancellationToken) => throw new NotImplementedException(); + public Task CreateSystemIdentity(User user, CancellationToken cancellationToken) => throw new NotImplementedException(); /// public Task CreateSystemIdentity(string username, string password, CancellationToken cancellationToken) => throw new NotImplementedException(); diff --git a/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs b/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs index 56b04356518..ca47a871929 100644 --- a/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs +++ b/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.DirectoryServices.AccountManagement; using System.Runtime.Versioning; using System.Security.Principal; @@ -12,8 +13,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Security { /// @@ -33,7 +32,7 @@ sealed class WindowsSystemIdentityFactory : ISystemIdentityFactory /// The input . /// The output username. /// The output domain name. May be . - static void GetUserAndDomainName(string input, out string username, out string domainName) + static void GetUserAndDomainName(string input, out string username, out string? domainName) { var splits = input.Split('\\'); username = splits.Length > 1 ? splits[1] : splits[0]; @@ -53,7 +52,7 @@ public WindowsSystemIdentityFactory(ILogger logger public ISystemIdentity GetCurrent() => new WindowsSystemIdentity(WindowsIdentity.GetCurrent()); /// - public Task CreateSystemIdentity(User user, CancellationToken cancellationToken) => Task.Factory.StartNew( + public Task CreateSystemIdentity(User user, CancellationToken cancellationToken) => Task.Factory.StartNew( () => { ArgumentNullException.ThrowIfNull(user); @@ -61,13 +60,12 @@ public Task CreateSystemIdentity(User user, CancellationToken c if (user.SystemIdentifier == null) throw new InvalidOperationException("User's SystemIdentifier must not be null!"); - PrincipalContext pc = null; - UserPrincipal principal = null; - + PrincipalContext? pc = null; GetUserAndDomainName(user.SystemIdentifier, out _, out var domainName); - bool TryGetPrincipalFromContextType(ContextType contextType) + bool TryGetPrincipalFromContextType(ContextType contextType, [NotNullWhen(true)] out UserPrincipal? principal) { + principal = null; try { pc = domainName != null @@ -100,7 +98,7 @@ bool TryGetPrincipalFromContextType(ContextType contextType) return principal != null; } - if (!TryGetPrincipalFromContextType(ContextType.Machine) && !TryGetPrincipalFromContextType(ContextType.Domain)) + if (!TryGetPrincipalFromContextType(ContextType.Machine, out var principal) && !TryGetPrincipalFromContextType(ContextType.Domain, out principal)) return null; return (ISystemIdentity)new WindowsSystemIdentity(principal); }, @@ -109,7 +107,7 @@ bool TryGetPrincipalFromContextType(ContextType contextType) TaskScheduler.Current); /// - public Task CreateSystemIdentity(string username, string password, CancellationToken cancellationToken) => Task.Factory.StartNew( + public Task CreateSystemIdentity(string username, string password, CancellationToken cancellationToken) => Task.Factory.StartNew( () => { ArgumentNullException.ThrowIfNull(username); diff --git a/src/Tgstation.Server.Host/System/NativeMethods.cs b/src/Tgstation.Server.Host/System/NativeMethods.cs index 234ba0661a4..ffba29cc9c2 100644 --- a/src/Tgstation.Server.Host/System/NativeMethods.cs +++ b/src/Tgstation.Server.Host/System/NativeMethods.cs @@ -83,7 +83,7 @@ public enum MiniDumpType : uint /// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa378184(v=vs.85).aspx. /// [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken); + public static extern bool LogonUser(string lpszUsername, string? lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken); /// /// See https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createsymboliclinkw. From dbf049dc0d57bb7b4385c17f9a1c5b1f2e5553d2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 13:18:55 -0500 Subject: [PATCH 342/717] Nullify `ISwarmOperations` --- src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs b/src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs index 8d3e198006c..dd9c01b7830 100644 --- a/src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs +++ b/src/Tgstation.Server.Host/Swarm/ISwarmOperations.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Swarm { /// From 0da3a49667beaba83cd2704d78758f5775486294 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 13:21:40 -0500 Subject: [PATCH 343/717] Nullify `ISwarmService` --- src/Tgstation.Server.Host/Swarm/ISwarmService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Swarm/ISwarmService.cs b/src/Tgstation.Server.Host/Swarm/ISwarmService.cs index c9e29bd0527..9b863895402 100644 --- a/src/Tgstation.Server.Host/Swarm/ISwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/ISwarmService.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Swarm { /// From e6f69f16bf691323098aa25443ea445f5514d26a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 13:21:52 -0500 Subject: [PATCH 344/717] Nullify `ISwarmServiceController` --- src/Tgstation.Server.Host/Swarm/ISwarmServiceController.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Swarm/ISwarmServiceController.cs b/src/Tgstation.Server.Host/Swarm/ISwarmServiceController.cs index 9f875ce05bd..34babd945ba 100644 --- a/src/Tgstation.Server.Host/Swarm/ISwarmServiceController.cs +++ b/src/Tgstation.Server.Host/Swarm/ISwarmServiceController.cs @@ -1,8 +1,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Swarm { /// From e22a6092ba95928ee1c7b846ffd014262bf91b04 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 13:22:05 -0500 Subject: [PATCH 345/717] Nullify `ISwarmUpdateAborter` --- src/Tgstation.Server.Host/Swarm/ISwarmUpdateAborter.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Swarm/ISwarmUpdateAborter.cs b/src/Tgstation.Server.Host/Swarm/ISwarmUpdateAborter.cs index 6cd79b99569..8d69505f272 100644 --- a/src/Tgstation.Server.Host/Swarm/ISwarmUpdateAborter.cs +++ b/src/Tgstation.Server.Host/Swarm/ISwarmUpdateAborter.cs @@ -1,7 +1,5 @@ using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Swarm { /// From 499860051d50680bdc48cc9774a2e1e0d215ade8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 13:22:18 -0500 Subject: [PATCH 346/717] Nullify `SwarmConstants` --- src/Tgstation.Server.Host/Swarm/SwarmConstants.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs b/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs index ec61a982bb3..988c60243ef 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmConstants.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Api; using Tgstation.Server.Host.Extensions.Converters; -#nullable disable - namespace Tgstation.Server.Host.Swarm { /// From 0d7f3a353cf778c8e70061efa28a226c5576e93d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 13:24:27 -0500 Subject: [PATCH 347/717] Nullify `SwarmServersUpdateRequest` --- src/Tgstation.Server.Host/Swarm/SwarmServersUpdateRequest.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Swarm/SwarmServersUpdateRequest.cs b/src/Tgstation.Server.Host/Swarm/SwarmServersUpdateRequest.cs index 2b3cdeaa23d..06fb6260bba 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmServersUpdateRequest.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmServersUpdateRequest.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Swarm { /// @@ -16,6 +14,6 @@ public sealed class SwarmServersUpdateRequest /// The of updated s. /// [Required] - public ICollection SwarmServers { get; set; } + public ICollection? SwarmServers { get; set; } } } From af0f05d8bff10819bfbe5b08d1148fc16a460d5e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 15:05:03 -0500 Subject: [PATCH 348/717] Nullify `SwarmService` Had to use many forgiveness operators here, but I've validated them in their current state --- .../Swarm/ISwarmService.cs | 2 +- .../Swarm/SwarmService.cs | 119 ++++++++++-------- .../Swarm/SwarmUpdateOperation.cs | 2 +- 3 files changed, 70 insertions(+), 53 deletions(-) diff --git a/src/Tgstation.Server.Host/Swarm/ISwarmService.cs b/src/Tgstation.Server.Host/Swarm/ISwarmService.cs index 9b863895402..8e827eb1319 100644 --- a/src/Tgstation.Server.Host/Swarm/ISwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/ISwarmService.cs @@ -38,6 +38,6 @@ public interface ISwarmService : ISwarmUpdateAborter /// Gets the list of s in the swarm, including the current one. /// /// A of s in the swarm. If the server is not part of a swarm, will be returned. - ICollection GetSwarmServers(); + ICollection? GetSwarmServers(); } } diff --git a/src/Tgstation.Server.Host/Swarm/SwarmService.cs b/src/Tgstation.Server.Host/Swarm/SwarmService.cs index d081050754b..7850f9e5e5c 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net; using System.Net.Http; @@ -26,8 +27,6 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Swarm { /// @@ -51,6 +50,7 @@ public bool ExpectedNumberOfNodesConnected /// /// If the swarm system is enabled. /// + [MemberNotNullWhen(true, nameof(serverHealthCheckTask), nameof(forceHealthCheckTcs), nameof(serverHealthCheckCancellationTokenSource), nameof(swarmServers))] bool SwarmMode => swarmConfiguration.PrivateKey != null; /// @@ -101,17 +101,17 @@ public bool ExpectedNumberOfNodesConnected /// /// The for . /// - readonly CancellationTokenSource serverHealthCheckCancellationTokenSource; + readonly CancellationTokenSource? serverHealthCheckCancellationTokenSource; /// /// of connected s. /// - readonly List swarmServers; + readonly List? swarmServers; /// /// of s to registration s and when they were created. /// - readonly Dictionary registrationIdsAndTimes; + readonly Dictionary? registrationIdsAndTimes; /// /// If the current server is the swarm controller. @@ -121,17 +121,17 @@ public bool ExpectedNumberOfNodesConnected /// /// A that is currently in progress. /// - volatile SwarmUpdateOperation updateOperation; + volatile SwarmUpdateOperation? updateOperation; /// /// A that is used to force a health check. /// - volatile TaskCompletionSource forceHealthCheckTcs; + volatile TaskCompletionSource? forceHealthCheckTcs; /// /// The for the . /// - Task serverHealthCheckTask; + Task? serverHealthCheckTask; /// /// The registration provided by the swarm controller. @@ -185,18 +185,17 @@ public SwarmService( { if (swarmConfiguration.Address == null) throw new InvalidOperationException("Swarm configuration missing Address!"); + if (String.IsNullOrWhiteSpace(swarmConfiguration.Identifier)) throw new InvalidOperationException("Swarm configuration missing Identifier!"); - } - swarmController = !SwarmMode || swarmConfiguration.ControllerAddress == null; - if (SwarmMode) - { - serverHealthCheckCancellationTokenSource = new CancellationTokenSource(); - forceHealthCheckTcs = new TaskCompletionSource(); + swarmController = swarmConfiguration.ControllerAddress == null; if (swarmController) registrationIdsAndTimes = new(); + serverHealthCheckCancellationTokenSource = new CancellationTokenSource(); + forceHealthCheckTcs = new TaskCompletionSource(); + swarmServers = new List { new SwarmServerResponse @@ -208,6 +207,8 @@ public SwarmService( }, }; } + else + swarmController = true; } /// @@ -348,7 +349,7 @@ async ValueTask SendRemoteCommitUpdate(SwarmServerResponse swarmServer) } /// - public ICollection GetSwarmServers() + public ICollection? GetSwarmServers() { if (!SwarmMode) return null; @@ -426,7 +427,7 @@ public async ValueTask Shutdown(CancellationToken cancellationToken) { logger.LogTrace("Begin Shutdown"); - async ValueTask SendUnregistrationRequest(SwarmServerResponse swarmServer) + async ValueTask SendUnregistrationRequest(SwarmServerResponse? swarmServer) { using var httpClient = httpClientFactory.CreateClient(); using var request = PrepareSwarmRequest( @@ -445,13 +446,13 @@ async ValueTask SendUnregistrationRequest(SwarmServerResponse swarmServer) logger.LogWarning( ex, "Error unregistering {nodeType}!", - swarmController + swarmServer != null ? $"node {swarmServer.Identifier}" : "from controller"); } } - if (serverHealthCheckTask != null) + if (SwarmMode && serverHealthCheckTask != null) { serverHealthCheckCancellationTokenSource.Cancel(); await serverHealthCheckTask; @@ -491,7 +492,7 @@ await databaseContextFactory.UseContext( .Select(SendUnregistrationRequest) .ToList()); swarmServers.RemoveRange(1, swarmServers.Count - 1); - registrationIdsAndTimes.Clear(); + registrationIdsAndTimes!.Clear(); } await task; @@ -506,6 +507,9 @@ public void UpdateSwarmServersList(IEnumerable swarmServers { ArgumentNullException.ThrowIfNull(swarmServers); + if (!SwarmMode) + throw new InvalidOperationException("Swarm mode not enabled!"); + if (swarmController) throw new InvalidOperationException("Cannot UpdateSwarmServersList on swarm controller!"); @@ -520,9 +524,12 @@ public void UpdateSwarmServersList(IEnumerable swarmServers /// public bool ValidateRegistration(Guid registrationId) { + if (!SwarmMode) + throw new InvalidOperationException("Swarm mode not enabled!"); + if (swarmController) lock (swarmServers) - return registrationIdsAndTimes.Values.Any(x => x.RegistrationId == registrationId); + return registrationIdsAndTimes!.Values.Any(x => x.RegistrationId == registrationId); if (registrationId != controllerRegistration) return false; @@ -542,6 +549,9 @@ public async ValueTask RegisterNode(Api.Models.Internal.SwarmServer node, if (node.Address == null) throw new ArgumentException("Node missing Address!", nameof(node)); + if (!SwarmMode) + throw new InvalidOperationException("Swarm mode not enabled!"); + if (!swarmController) throw new InvalidOperationException("Cannot RegisterNode on swarm node!"); @@ -549,6 +559,7 @@ public async ValueTask RegisterNode(Api.Models.Internal.SwarmServer node, await AbortUpdate(); + var registrationIdsAndTimes = this.registrationIdsAndTimes!; lock (swarmServers) { if (registrationIdsAndTimes.Any(x => x.Value.RegistrationId == registrationId)) @@ -642,6 +653,9 @@ public async ValueTask RemoteCommitReceived(Guid registrationId, Cancellat /// public async ValueTask UnregisterNode(Guid registrationId, CancellationToken cancellationToken) { + if (!SwarmMode) + throw new InvalidOperationException("Swarm mode not enabled!"); + logger.LogTrace("UnregisterNode {registrationId}", registrationId); await AbortUpdate(); @@ -663,7 +677,7 @@ public async ValueTask UnregisterNode(Guid registrationId, CancellationToken can lock (swarmServers) { swarmServers.RemoveAll(x => x.Identifier == nodeIdentifier); - registrationIdsAndTimes.Remove(nodeIdentifier); + registrationIdsAndTimes!.Remove(nodeIdentifier); } MarkServersDirty(); @@ -710,7 +724,7 @@ async ValueTask SendRemoteAbort(SwarmServerResponse swarmServer) Address = swarmConfiguration.ControllerAddress, }); - lock (swarmServers) + lock (swarmServers!) return ValueTaskExtensions.WhenAll( swarmServers .Where(x => !x.Controller) @@ -760,7 +774,7 @@ RequestFileStreamProvider CreateUpdateStreamProvider(SwarmServerResponse sourceN /// The . Must always have populated. If is , it must be fully populated. /// The for the operation. /// A resulting in the . - async ValueTask PrepareUpdateImpl(ISeekableFileStreamProvider initiatorProvider, SwarmUpdateRequest updateRequest, CancellationToken cancellationToken) + async ValueTask PrepareUpdateImpl(ISeekableFileStreamProvider? initiatorProvider, SwarmUpdateRequest updateRequest, CancellationToken cancellationToken) { if (!SwarmMode) { @@ -777,7 +791,7 @@ async ValueTask PrepareUpdateImpl(ISeekableFileStreamProvide SwarmUpdateOperation localUpdateOperation; try { - SwarmServerResponse sourceNode = null; + SwarmServerResponse? sourceNode = null; List currentNodes; lock (swarmServers) { @@ -814,7 +828,7 @@ async ValueTask PrepareUpdateImpl(ISeekableFileStreamProvide if (!swarmController && initiator) { - var downloadTickets = await CreateDownloadTickets(initiatorProvider, currentNodes, cancellationToken); + var downloadTickets = await CreateDownloadTickets(initiatorProvider!, currentNodes, cancellationToken); // condition of initiator logger.LogInformation("Forwarding update request to swarm controller..."); using var httpClient = httpClientFactory.CreateClient(); @@ -854,7 +868,7 @@ async ValueTask PrepareUpdateImpl(ISeekableFileStreamProvide return SwarmPrepareResult.Failure; } - if (!updateRequest.DownloadTickets.TryGetValue(swarmConfiguration.Identifier, out var ticket)) + if (!updateRequest.DownloadTickets.TryGetValue(swarmConfiguration.Identifier!, out var ticket)) { logger.Log( swarmController @@ -924,7 +938,7 @@ async ValueTask PrepareUpdateImpl(ISeekableFileStreamProvide /// The for the operation. /// A resulting in the . async ValueTask ControllerDistributedPrepareUpdate( - ISeekableFileStreamProvider initiatorProvider, + ISeekableFileStreamProvider? initiatorProvider, SwarmUpdateRequest updateRequest, SwarmUpdateOperation currentUpdateOperation, CancellationToken cancellationToken) @@ -967,7 +981,7 @@ async ValueTask ControllerDistributedPrepareUpdate( } var downloadTicketDictionary = weAreInitiator - ? await CreateDownloadTickets(initiatorProvider, currentUpdateOperation.InvolvedServers, cancellationToken) + ? await CreateDownloadTickets(initiatorProvider!, currentUpdateOperation.InvolvedServers, cancellationToken) : updateRequest.DownloadTickets; var sourceNode = weAreInitiator @@ -984,18 +998,19 @@ async ValueTask ControllerDistributedPrepareUpdate( .Select(node => { // only send the necessary ticket to each node from the controller - Dictionary localTicketDictionary; - if (!downloadTicketDictionary.TryGetValue(node.Identifier, out var ticket) - && node.Identifier != sourceNode) + Dictionary localTicketDictionary; + var nodeId = node.Identifier!; + if (!downloadTicketDictionary.TryGetValue(nodeId, out var ticket) + && nodeId != sourceNode) { - logger.LogError("Missing download ticket for node {missingNodeId}!", node.Identifier); + logger.LogError("Missing download ticket for node {missingNodeId}!", nodeId); anyFailed = true; return null; } else - localTicketDictionary = new Dictionary + localTicketDictionary = new Dictionary { - { node.Identifier, ticket }, + { nodeId, ticket }, }; var request = new SwarmUpdateRequest @@ -1015,7 +1030,7 @@ async ValueTask ControllerDistributedPrepareUpdate( var tasks = updateRequests .Select(async tuple => { - var node = tuple.Item1; + var node = tuple!.Item1; var body = tuple.Item2; using var request = PrepareSwarmRequest( @@ -1088,7 +1103,7 @@ async ValueTask> CreateDownloadTickets( var downloadTickets = new Dictionary(serversRequiringTickets.Count); foreach (var node in serversRequiringTickets) downloadTickets.Add( - node.Identifier, + node.Identifier!, transferService.CreateDownload(downloadProvider)); await streamRetrievalTask; @@ -1105,9 +1120,10 @@ async ValueTask HealthCheckNodes(CancellationToken cancellationToken) using var httpClient = httpClientFactory.CreateClient(); List currentSwarmServers; - lock (swarmServers) + lock (swarmServers!) currentSwarmServers = swarmServers.ToList(); + var registrationIdsAndTimes = this.registrationIdsAndTimes!; async ValueTask HealthRequestForServer(SwarmServerResponse swarmServer) { using var request = PrepareSwarmRequest( @@ -1133,14 +1149,14 @@ async ValueTask HealthRequestForServer(SwarmServerResponse swarmServer) lock (swarmServers) { swarmServers.Remove(swarmServer); - registrationIdsAndTimes.Remove(swarmServer.Identifier); + registrationIdsAndTimes.Remove(swarmServer.Identifier!); } } await ValueTaskExtensions.WhenAll( currentSwarmServers .Where(node => !node.Controller - && registrationIdsAndTimes.TryGetValue(node.Identifier, out var registrationAndTime) + && registrationIdsAndTimes.TryGetValue(node.Identifier!, out var registrationAndTime) && registrationAndTime.RegisteredAt.AddMinutes(SwarmConstants.ControllerHealthCheckIntervalMinutes) < DateTimeOffset.UtcNow) .Select(HealthRequestForServer)); @@ -1169,7 +1185,7 @@ void MarkServersDirty() bool TriggerHealthCheck() { var currentTcs = Interlocked.Exchange(ref forceHealthCheckTcs, new TaskCompletionSource()); - return currentTcs.TrySetResult(); + return currentTcs!.TrySetResult(); } /// @@ -1299,7 +1315,7 @@ async ValueTask RegisterWithController(CancellationToke async ValueTask SendUpdatedServerListToNodes(CancellationToken cancellationToken) { List currentSwarmServers; - lock (swarmServers) + lock (swarmServers!) { serversDirty = false; currentSwarmServers = swarmServers.ToList(); @@ -1337,7 +1353,7 @@ async ValueTask UpdateRequestForServer(SwarmServerResponse swarmServer) lock (swarmServers) { swarmServers.Remove(swarmServer); - registrationIdsAndTimes.Remove(swarmServer.Identifier); + registrationIdsAndTimes!.Remove(swarmServer.Identifier!); } } } @@ -1352,17 +1368,17 @@ await ValueTaskExtensions.WhenAll( /// /// Prepares a for swarm communication. /// - /// The the message is for, if null will be sent to swarm controller. + /// The the message is for. Must have and set. If , will be sent to swarm controller. /// The . /// The route on to use. /// The body if any. /// An optional override to the . /// A new . HttpRequestMessage PrepareSwarmRequest( - SwarmServerResponse swarmServer, + SwarmServerResponse? swarmServer, HttpMethod httpMethod, string route, - object body, + object? body, Guid? registrationIdOverride = null) { swarmServer ??= new SwarmServerResponse @@ -1375,7 +1391,7 @@ HttpRequestMessage PrepareSwarmRequest( "{method} {route} to swarm server {nodeIdOrAddress}", httpMethod, fullRoute, - swarmServer.Identifier ?? swarmServer.Address.ToString()); + swarmServer.Identifier ?? swarmServer.Address!.ToString()); var request = new HttpRequestMessage( httpMethod, @@ -1390,8 +1406,8 @@ HttpRequestMessage PrepareSwarmRequest( request.Headers.Add(SwarmConstants.RegistrationIdHeader, registrationIdOverride.Value.ToString()); else if (swarmController) { - lock (swarmServers) - if (registrationIdsAndTimes.TryGetValue(swarmServer.Identifier, out var registrationIdAndTime)) + lock (swarmServers!) + if (registrationIdsAndTimes!.TryGetValue(swarmServer.Identifier!, out var registrationIdAndTime)) request.Headers.Add(SwarmConstants.RegistrationIdHeader, registrationIdAndTime.RegistrationId.ToString()); } else if (controllerRegistration.HasValue) @@ -1422,7 +1438,7 @@ async Task HealthCheckLoop(CancellationToken cancellationToken) logger.LogTrace("Starting HealthCheckLoop..."); try { - var nextForceHealthCheckTask = forceHealthCheckTcs.Task; + var nextForceHealthCheckTask = forceHealthCheckTcs!.Task; while (!cancellationToken.IsCancellationRequested) { TimeSpan delay; @@ -1500,13 +1516,14 @@ async Task HealthCheckLoop(CancellationToken cancellationToken) /// /// The registration . /// The registered or if it does not exist. - string NodeIdentifierFromRegistration(Guid registrationId) + string? NodeIdentifierFromRegistration(Guid registrationId) { if (!swarmController) throw new InvalidOperationException("NodeIdentifierFromRegistration on node!"); - lock (swarmServers) + lock (swarmServers!) { + var registrationIdsAndTimes = this.registrationIdsAndTimes!; var exists = registrationIdsAndTimes.Any(x => x.Value.RegistrationId == registrationId); if (!exists) { diff --git a/src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs b/src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs index 3ebe8576e24..56d7496a262 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs @@ -60,7 +60,7 @@ public SwarmUpdateOperation(Version targetVersion) /// Initializes a new instance of the class. /// /// The value of . - /// An of the controller's current nodes as s. + /// An of the controller's current nodes as s. Must have and set. /// This is the variant for use by the controller. public SwarmUpdateOperation(Version targetVersion, IEnumerable currentNodes) : this(targetVersion) From 1e21ef20b8a161dfbd0f2cf861b3eba213c65c46 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 15:05:56 -0500 Subject: [PATCH 349/717] Nullify `SwarmUpdateOperation` --- src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs b/src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs index 56d7496a262..67d65686ca8 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmUpdateOperation.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Swarm { /// @@ -33,7 +31,7 @@ public class SwarmUpdateOperation /// /// Backing field for . /// - readonly IReadOnlyList initialInvolvedServers; + readonly IReadOnlyList? initialInvolvedServers; /// /// The backing for . @@ -43,7 +41,7 @@ public class SwarmUpdateOperation /// /// of that need to send a ready-commit to the controller before the commit can happen. /// - readonly HashSet nodesThatNeedToBeReadyToCommit; + readonly HashSet? nodesThatNeedToBeReadyToCommit; /// /// Initializes a new instance of the class. @@ -68,7 +66,7 @@ public SwarmUpdateOperation(Version targetVersion, IEnumerable !node.Controller) - .Select(node => node.Identifier) + .Select(node => node.Identifier!) .ToHashSet(); } From 9069d9a958a17b120ec225721c7b029a18c3043d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 15:45:03 -0500 Subject: [PATCH 350/717] Fix appsettings base path not getting passed in service --- src/Tgstation.Server.Host.Service/ServerService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host.Service/ServerService.cs b/src/Tgstation.Server.Host.Service/ServerService.cs index 56491187fbb..0ab3a73cb69 100644 --- a/src/Tgstation.Server.Host.Service/ServerService.cs +++ b/src/Tgstation.Server.Host.Service/ServerService.cs @@ -104,7 +104,7 @@ protected override void OnStart(string[] args) Stop, signalChecker => watchdogFactory.CreateWatchdog(signalChecker, loggerFactory.Value), loggerFactory.Value.CreateLogger(), - args); + newArgs.ToArray()); } /// From bd20e37d3d4b9018f8878ea74f657dbb58805c9b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 15:32:15 -0500 Subject: [PATCH 351/717] Nullify `SwarmUpdateRequest` --- .../Swarm/SwarmService.cs | 23 ++++++++++++------- .../Swarm/SwarmUpdateRequest.cs | 8 +++---- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/Tgstation.Server.Host/Swarm/SwarmService.cs b/src/Tgstation.Server.Host/Swarm/SwarmService.cs index 7850f9e5e5c..cd0e855151a 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmService.cs @@ -776,14 +776,14 @@ RequestFileStreamProvider CreateUpdateStreamProvider(SwarmServerResponse sourceN /// A resulting in the . async ValueTask PrepareUpdateImpl(ISeekableFileStreamProvider? initiatorProvider, SwarmUpdateRequest updateRequest, CancellationToken cancellationToken) { + var version = updateRequest.UpdateVersion!; if (!SwarmMode) { // we still need an active update operation for the TargetVersion - updateOperation = new SwarmUpdateOperation(updateRequest.UpdateVersion); + updateOperation = new SwarmUpdateOperation(version); return SwarmPrepareResult.SuccessProviderNotRequired; } - var version = updateRequest.UpdateVersion; var initiator = initiatorProvider != null; logger.LogTrace("PrepareUpdateImpl {version}...", version); @@ -868,6 +868,12 @@ async ValueTask PrepareUpdateImpl(ISeekableFileStreamProvide return SwarmPrepareResult.Failure; } + if (updateRequest.DownloadTickets == null) + { + logger.LogError("Missing download tickets in update request!"); + return SwarmPrepareResult.Failure; + } + if (!updateRequest.DownloadTickets.TryGetValue(swarmConfiguration.Identifier!, out var ticket)) { logger.Log( @@ -970,7 +976,7 @@ async ValueTask ControllerDistributedPrepareUpdate( } // The initiator node obviously doesn't create a ticket for itself - else if (!weAreInitiator && updateRequest.DownloadTickets.Count != currentUpdateOperation.InvolvedServers.Count - 1) + else if (!weAreInitiator && updateRequest.DownloadTickets!.Count != currentUpdateOperation.InvolvedServers.Count - 1) { logger.LogWarning( "Aborting update, {receivedTickets} download tickets were provided but there are {nodesToUpdate} nodes in the swarm that require the package!", @@ -982,7 +988,7 @@ async ValueTask ControllerDistributedPrepareUpdate( var downloadTicketDictionary = weAreInitiator ? await CreateDownloadTickets(initiatorProvider!, currentUpdateOperation.InvolvedServers, cancellationToken) - : updateRequest.DownloadTickets; + : updateRequest.DownloadTickets!; var sourceNode = weAreInitiator ? swarmConfiguration.Identifier @@ -998,17 +1004,18 @@ async ValueTask ControllerDistributedPrepareUpdate( .Select(node => { // only send the necessary ticket to each node from the controller - Dictionary localTicketDictionary; + Dictionary? localTicketDictionary; var nodeId = node.Identifier!; - if (!downloadTicketDictionary.TryGetValue(nodeId, out var ticket) - && nodeId != sourceNode) + if (nodeId == sourceNode) + localTicketDictionary = null; + else if (!downloadTicketDictionary.TryGetValue(nodeId, out var ticket)) { logger.LogError("Missing download ticket for node {missingNodeId}!", nodeId); anyFailed = true; return null; } else - localTicketDictionary = new Dictionary + localTicketDictionary = new Dictionary { { nodeId, ticket }, }; diff --git a/src/Tgstation.Server.Host/Swarm/SwarmUpdateRequest.cs b/src/Tgstation.Server.Host/Swarm/SwarmUpdateRequest.cs index a0d7b0fe5ca..958a8f5afb8 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmUpdateRequest.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmUpdateRequest.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Swarm { /// @@ -17,17 +15,17 @@ public sealed class SwarmUpdateRequest /// The TGS to update to. /// [Required] - public Version UpdateVersion { get; init; } + public Version? UpdateVersion { get; init; } /// /// The of the node to download the update package from. /// [Required] - public string SourceNode { get; init; } + public string? SourceNode { get; init; } /// /// The map of s to s for retrieving the update package from the initiating server. /// - public Dictionary DownloadTickets { get; init; } + public Dictionary? DownloadTickets { get; init; } } } From ffcea66b248f3143d3ee7a331b278553bab1b963 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:01:15 -0500 Subject: [PATCH 352/717] Nullify `DiscordOAuthValidator` --- .../Security/OAuth/DiscordOAuthValidator.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs index 166ff85f277..3195ec9dcf3 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Security.OAuth { /// From 2f78ebf147dafc800e9558f09e7a786603ad81e6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:02:39 -0500 Subject: [PATCH 353/717] Nullify `GenericOAuthValidator` --- .../Security/OAuth/GenericOAuthValidator.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs index 0885546d117..5963023b0fc 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs @@ -16,8 +16,6 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Security.OAuth { /// @@ -82,11 +80,11 @@ public GenericOAuthValidator( } /// - public async ValueTask ValidateResponseCode(string code, CancellationToken cancellationToken) + public async ValueTask ValidateResponseCode(string code, CancellationToken cancellationToken) { using var httpClient = CreateHttpClient(); - string tokenResponsePayload = null; - string userInformationPayload = null; + string? tokenResponsePayload = null; + string? userInformationPayload = null; try { Logger.LogTrace("Validating response code..."); @@ -99,7 +97,7 @@ public async ValueTask ValidateResponseCode(string code, CancellationTok tokenRequestPayload, SerializerSettings()); - var tokenRequestDictionary = JsonConvert.DeserializeObject>(tokenRequestJson); + var tokenRequestDictionary = JsonConvert.DeserializeObject>(tokenRequestJson)!; tokenRequest.Content = new FormUrlEncodedContent(tokenRequestDictionary); using var tokenResponse = await httpClient.SendAsync(tokenRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken); From e895f796f501ce1182af852f28ab70554780322d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:03:03 -0500 Subject: [PATCH 354/717] Nullify `GitHubOAuthValidator` --- .../Security/OAuth/GitHubOAuthValidator.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/OAuth/GitHubOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/GitHubOAuthValidator.cs index d6ed38808b7..3f3180f9da2 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/GitHubOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/GitHubOAuthValidator.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Utils.GitHub; -#nullable disable - namespace Tgstation.Server.Host.Security.OAuth { /// @@ -54,7 +52,7 @@ public GitHubOAuthValidator( } /// - public async ValueTask ValidateResponseCode(string code, CancellationToken cancellationToken) + public async ValueTask ValidateResponseCode(string code, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(code); From 870e0b565293bd9cd4e167801b3fba5caee7e788 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:03:22 -0500 Subject: [PATCH 355/717] Nullify `InvisionCommunityOAuthValidator` --- .../Security/OAuth/InvisionCommunityOAuthValidator.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs index 14382d58388..0e912bd3688 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs @@ -6,15 +6,13 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Security.OAuth { /// /// OAuth validator for Invision Community (selfhosted). /// sealed class InvisionCommunityOAuthValidator : GenericOAuthValidator - { + { /// public override OAuthProvider Provider => OAuthProvider.InvisionCommunity; From 991b4075803f65063d7c0bb1114f116ceb23ede4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:03:57 -0500 Subject: [PATCH 356/717] Nullify `IOAuthProviders` --- src/Tgstation.Server.Host/Security/OAuth/IOAuthProviders.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/OAuth/IOAuthProviders.cs b/src/Tgstation.Server.Host/Security/OAuth/IOAuthProviders.cs index c7e9a062748..2da6651c041 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/IOAuthProviders.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/IOAuthProviders.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Api.Models; -#nullable disable - namespace Tgstation.Server.Host.Security.OAuth { /// @@ -16,7 +14,7 @@ public interface IOAuthProviders /// /// The to get the validator for. /// The for . - IOAuthValidator GetValidator(OAuthProvider oAuthProvider); + IOAuthValidator? GetValidator(OAuthProvider oAuthProvider); /// /// Gets a of the provider client IDs. From 47c729fdf4f8987d2789ed54aeec2022719cb786 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:04:17 -0500 Subject: [PATCH 357/717] Nullify `IOAuthValidator` --- src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs index 402fb5efe7a..472a7ff091d 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Api.Models; -#nullable disable - namespace Tgstation.Server.Host.Security.OAuth { /// @@ -29,6 +27,6 @@ public interface IOAuthValidator /// The OAuth response string from web application. /// The for the operation. /// A resulting in if authentication failed, if a rate limit occurred, and the validated otherwise. - ValueTask ValidateResponseCode(string code, CancellationToken cancellationToken); + ValueTask ValidateResponseCode(string code, CancellationToken cancellationToken); } } From 302c458e745311dc470a24332f3f0a59e6b490dd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:04:39 -0500 Subject: [PATCH 358/717] Nullify `KeycloakOAuthValidator` --- .../Security/OAuth/KeycloakOAuthValidator.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs index 1152398d6af..f4e61b4b5ce 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Security.OAuth { /// From d781370bc7844d4d437ccb81c66a2c02fc8123f0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:05:02 -0500 Subject: [PATCH 359/717] Nullify `OAuthProviders` --- src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs b/src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs index 7e0e1a308c0..9d28ab1c824 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Utils.GitHub; -#nullable disable - namespace Tgstation.Server.Host.Security.OAuth { /// @@ -82,7 +80,7 @@ public OAuthProviders( } /// - public IOAuthValidator GetValidator(OAuthProvider oAuthProvider) => validators.FirstOrDefault(x => x.Provider == oAuthProvider); + public IOAuthValidator? GetValidator(OAuthProvider oAuthProvider) => validators.FirstOrDefault(x => x.Provider == oAuthProvider); /// public Dictionary ProviderInfos() From 5dbba020e54bf9cb0df655750cd4fa7008d82962 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:05:32 -0500 Subject: [PATCH 360/717] Nullify `OAuthTokenRequest` --- src/Tgstation.Server.Host/Security/OAuth/OAuthTokenRequest.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/OAuth/OAuthTokenRequest.cs b/src/Tgstation.Server.Host/Security/OAuth/OAuthTokenRequest.cs index 2c7721f4aff..a3955ceaff6 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/OAuthTokenRequest.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/OAuthTokenRequest.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Security.OAuth { /// @@ -24,7 +22,7 @@ sealed class OAuthTokenRequest : OAuthConfigurationBase /// /// The OAuth redirect URI. /// - public Uri RedirectUri { get; } + public Uri? RedirectUri { get; } /// /// The OAuth grant type. From 7cc0d477fb7f5154fad2a24e44dd75416c578317 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:05:43 -0500 Subject: [PATCH 361/717] Nullify `TGForumsOAuthValidator` --- .../Security/OAuth/TGForumsOAuthValidator.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/OAuth/TGForumsOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/TGForumsOAuthValidator.cs index 36b213b6d98..c81a54ec738 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/TGForumsOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/TGForumsOAuthValidator.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Security.OAuth { /// From dc1040e4225e5bd63c5901c47ed0db3382ec7f2c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:06:13 -0500 Subject: [PATCH 362/717] Nullify `IPostSetupServices` --- src/Tgstation.Server.Host/Setup/IPostSetupServices.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs b/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs index aaa785f4131..21264d9277e 100644 --- a/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs +++ b/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs @@ -1,8 +1,6 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Setup { /// From c479b0b31db012fbf50506cfa04f64235f9f840c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:06:35 -0500 Subject: [PATCH 363/717] Nullify `IPostSetupServices` --- .../Setup/IPostSetupServices{TLoggerType}.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs b/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs index 25024af43db..f36d9526e78 100644 --- a/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs +++ b/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs @@ -1,7 +1,5 @@ using Microsoft.Extensions.Logging; -#nullable disable - namespace Tgstation.Server.Host.Setup { /// From 65f26d7d312ab874479b96641dd69ff4a7a90a17 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:07:10 -0500 Subject: [PATCH 364/717] Nullify `PostSetupServices` --- src/Tgstation.Server.Host/Setup/PostSetupServices.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Setup/PostSetupServices.cs b/src/Tgstation.Server.Host/Setup/PostSetupServices.cs index 4fce4e6075e..c1ace340ec5 100644 --- a/src/Tgstation.Server.Host/Setup/PostSetupServices.cs +++ b/src/Tgstation.Server.Host/Setup/PostSetupServices.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Setup { /// From f33c46c0207ae697440ca318c1e044e5652a4fa4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:07:27 -0500 Subject: [PATCH 365/717] Nullify `SetupApplication` --- src/Tgstation.Server.Host/Setup/SetupApplication.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Setup/SetupApplication.cs b/src/Tgstation.Server.Host/Setup/SetupApplication.cs index ca4b64be58d..56c590ce7d0 100644 --- a/src/Tgstation.Server.Host/Setup/SetupApplication.cs +++ b/src/Tgstation.Server.Host/Setup/SetupApplication.cs @@ -12,8 +12,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Setup { /// From d619571871d1d8a1f3287320b76fda8cd8b0ecfb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:11:03 -0500 Subject: [PATCH 366/717] Nullify `SetupWizard` --- .../Setup/SetupWizard.cs | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index d4611f4465d..c164b9d3335 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -31,8 +31,6 @@ using YamlDotNet.Serialization; -#nullable disable - namespace Tgstation.Server.Host.Setup { /// @@ -222,9 +220,12 @@ async ValueTask TestDatabaseConnection( await console.WriteAsync($"Checking {databaseConfiguration.DatabaseType} version...", true, cancellationToken); using var command = testConnection.CreateCommand(); command.CommandText = "SELECT VERSION()"; - var fullVersion = (string)await command.ExecuteScalarAsync(cancellationToken); + var fullVersion = (string?)await command.ExecuteScalarAsync(cancellationToken); await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "Found {0}", fullVersion), true, cancellationToken); + if (fullVersion == null) + throw new InvalidOperationException($"\"{command.CommandText}\" returned null!"); + if (databaseConfiguration.DatabaseType == DatabaseType.PostgresSql) { var splits = fullVersion.Split(' '); @@ -293,7 +294,7 @@ async ValueTask TestDatabaseConnection( /// The path to the potential SQLite database file. /// The for the operation. /// A resulting in the SQLite database path to store in the configuration. - async ValueTask ValidateNonExistantSqliteDBName(string databaseName, CancellationToken cancellationToken) + async ValueTask ValidateNonExistantSqliteDBName(string databaseName, CancellationToken cancellationToken) { var dbPathIsRooted = Path.IsPathRooted(databaseName); var resolvedPath = ioManager.ResolvePath( @@ -408,12 +409,12 @@ async ValueTask ConfigureDatabase(CancellationToken cance DatabaseType = await PromptDatabaseType(firstTime, cancellationToken), }; - string serverAddress = null; + string? serverAddress = null; ushort? serverPort = null; var definitelyLocalMariaDB = firstTime && internalConfiguration.MariaDBSetup; var isSqliteDB = databaseConfiguration.DatabaseType == DatabaseType.Sqlite; - IPHostEntry serverAddressEntry = null; + IPHostEntry? serverAddressEntry = null; if (!isSqliteDB) do { @@ -470,7 +471,7 @@ async ValueTask ConfigureDatabase(CancellationToken cance await console.WriteAsync(null, true, cancellationToken); await console.WriteAsync($"Enter the database {(isSqliteDB ? "file path" : "name")} ({(definitelyLocalMariaDB ? "leave blank for \"tgs\")" : "Can be from previous installation. Otherwise, should not exist")}): ", false, cancellationToken); - string databaseName; + string? databaseName; bool dbExists = false; do { @@ -512,8 +513,8 @@ async ValueTask ConfigureDatabase(CancellationToken cance await console.WriteAsync(null, true, cancellationToken); - string username = null; - string password = null; + string? username = null; + string? password = null; if (!isSqliteDB) if (!useWinAuth) { @@ -885,7 +886,7 @@ async ValueTask ConfigureControlPanel(CancellationTok /// /// The for the operation. /// A resulting in the new . - async ValueTask ConfigureSwarm(CancellationToken cancellationToken) + async ValueTask ConfigureSwarm(CancellationToken cancellationToken) { var enable = await PromptYesNo("Enable swarm mode?", false, cancellationToken); if (!enable) @@ -902,7 +903,7 @@ async ValueTask ConfigureSwarm(CancellationToken cancellatio async ValueTask ParseAddress(string question) { var first = true; - Uri address; + Uri? address; do { if (first) @@ -933,7 +934,7 @@ async ValueTask ParseAddress(string question) while (String.IsNullOrWhiteSpace(privateKey)); var controller = await PromptYesNo("Is this server the swarm's controller? (y/n): ", null, cancellationToken); - Uri controllerAddress = null; + Uri? controllerAddress = null; if (!controller) controllerAddress = await ParseAddress("Enter the swarm controller's HTTP(S) address: "); @@ -965,15 +966,15 @@ async ValueTask SaveConfiguration( ushort? hostingPort, DatabaseConfiguration databaseConfiguration, GeneralConfiguration newGeneralConfiguration, - FileLoggingConfiguration fileLoggingConfiguration, - ElasticsearchConfiguration elasticsearchConfiguration, + FileLoggingConfiguration? fileLoggingConfiguration, + ElasticsearchConfiguration? elasticsearchConfiguration, ControlPanelConfiguration controlPanelConfiguration, - SwarmConfiguration swarmConfiguration, + SwarmConfiguration? swarmConfiguration, CancellationToken cancellationToken) { newGeneralConfiguration.ApiPort = hostingPort ?? GeneralConfiguration.DefaultApiPort; newGeneralConfiguration.ConfigVersion = GeneralConfiguration.CurrentConfigVersion; - var map = new Dictionary() + var map = new Dictionary() { { DatabaseConfiguration.Section, databaseConfiguration }, { GeneralConfiguration.Section, newGeneralConfiguration }, @@ -1097,7 +1098,7 @@ async Task HandleSetupCancel() } Task finalTask = Task.CompletedTask; - string originalConsoleTitle = null; + string? originalConsoleTitle = null; void SetConsoleTitle() { if (originalConsoleTitle != null) From 2b69e9078fde5d52e4585b7e20ce63a8c38ffb9a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:11:27 -0500 Subject: [PATCH 367/717] Nullify `IServer` --- src/Tgstation.Server.Host/IServer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/IServer.cs b/src/Tgstation.Server.Host/IServer.cs index 105b14f7736..e13364831f6 100644 --- a/src/Tgstation.Server.Host/IServer.cs +++ b/src/Tgstation.Server.Host/IServer.cs @@ -1,8 +1,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host { /// From 03cfae1796810709e8dee67c2063c81ad61ce6f8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:12:29 -0500 Subject: [PATCH 368/717] Nullify `MasterVersionsAttribute` --- .../Properties/MasterVersionsAttribute.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs index 042b679202f..d77bcd349bc 100644 --- a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs +++ b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs @@ -1,8 +1,6 @@ using System; using System.Reflection; -#nullable disable - namespace Tgstation.Server.Host.Properties { /// @@ -16,7 +14,7 @@ sealed class MasterVersionsAttribute : Attribute /// public static MasterVersionsAttribute Instance => Assembly .GetExecutingAssembly() - .GetCustomAttribute(); + .GetCustomAttribute()!; /// /// The of the version built. From 48313dc7b8a0b920447894916e6548c9dddb55ef Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:12:54 -0500 Subject: [PATCH 369/717] Nullify `LimitedStreamResult` --- .../Controllers/Results/LimitedStreamResult.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResult.cs b/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResult.cs index 10b0e08909c..998f5779c5c 100644 --- a/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResult.cs +++ b/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResult.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Controllers.Results { /// From 53bcad8fa5428ed8534f327e7aa4d39ac280e381 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:15:19 -0500 Subject: [PATCH 370/717] Nullify `LimitedStreamResultExecutor` --- .../Controllers/Results/LimitedStreamResultExecutor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResultExecutor.cs b/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResultExecutor.cs index 2a7bc72279b..c3d3b7d3728 100644 --- a/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResultExecutor.cs +++ b/src/Tgstation.Server.Host/Controllers/Results/LimitedStreamResultExecutor.cs @@ -7,8 +7,6 @@ using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.Logging; -#nullable disable - namespace Tgstation.Server.Host.Controllers.Results { /// @@ -55,7 +53,7 @@ await StreamCopyOperation.CopyToAsync( } else { - stream.Seek(range.From.Value, SeekOrigin.Begin); + stream.Seek(range.From ?? 0, SeekOrigin.Begin); await StreamCopyOperation.CopyToAsync( stream, outputStream, From 54beb2dbc62d79f0175465acc124ce3031bc8e3a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:17:09 -0500 Subject: [PATCH 371/717] Nullify `PaginatableResult` --- .../Controllers/Results/PaginatableResult.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/Results/PaginatableResult.cs b/src/Tgstation.Server.Host/Controllers/Results/PaginatableResult.cs index 7be3c27aa19..5d4f80d0237 100644 --- a/src/Tgstation.Server.Host/Controllers/Results/PaginatableResult.cs +++ b/src/Tgstation.Server.Host/Controllers/Results/PaginatableResult.cs @@ -1,10 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.AspNetCore.Mvc; -#nullable disable - namespace Tgstation.Server.Host.Controllers.Results { /// @@ -13,15 +12,22 @@ namespace Tgstation.Server.Host.Controllers.Results /// The of model intended to be returned. public sealed class PaginatableResult { + /// + /// Whether or not the is valid. + /// + [MemberNotNullWhen(true, nameof(Results))] + [MemberNotNullWhen(false, nameof(EarlyOut))] + public bool Valid => EarlyOut == null; + /// /// The results. /// - public IOrderedQueryable Results { get; } + public IOrderedQueryable? Results { get; } /// /// An to return immediately. /// - public IActionResult EarlyOut { get; } + public IActionResult? EarlyOut { get; } /// /// Initializes a new instance of the class. From 1d8959ddcd88f20b5ce8f03f75c36a3052aa8a79 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:18:37 -0500 Subject: [PATCH 372/717] Nullify `AdministrationController` --- .../Models/Response/ServerUpdateResponse.cs | 2 +- .../Controllers/AdministrationController.cs | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/Response/ServerUpdateResponse.cs b/src/Tgstation.Server.Api/Models/Response/ServerUpdateResponse.cs index 3578e6cd0ae..48c9b99e6a1 100644 --- a/src/Tgstation.Server.Api/Models/Response/ServerUpdateResponse.cs +++ b/src/Tgstation.Server.Api/Models/Response/ServerUpdateResponse.cs @@ -20,7 +20,7 @@ public sealed class ServerUpdateResponse : FileTicketResponse /// The value of . /// The optional value of . [JsonConstructor] - public ServerUpdateResponse(Version newVersion, string fileTicket) + public ServerUpdateResponse(Version newVersion, string? fileTicket) { NewVersion = newVersion ?? throw new ArgumentNullException(nameof(newVersion)); FileTicket = fileTicket; diff --git a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs index f90a842a5c1..2ccc4f4c8bc 100644 --- a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs +++ b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs @@ -29,8 +29,6 @@ using Tgstation.Server.Host.Utils; using Tgstation.Server.Host.Utils.GitHub; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -146,8 +144,8 @@ public async ValueTask Read(CancellationToken cancellationToken) { try { - Version greatestVersion = null; - Uri repoUrl = null; + Version? greatestVersion = null; + Uri? repoUrl = null; try { var gitHubService = gitHubServiceFactory.CreateService(); @@ -215,10 +213,10 @@ public async ValueTask Update([FromBody] ServerUpdateRequest mode var attemptingUpload = model.UploadZip == true; if (attemptingUpload) { - if (!AuthenticationContext.PermissionSet.AdministrationRights.Value.HasFlag(AdministrationRights.UploadVersion)) + if (!AuthenticationContext.PermissionSet.AdministrationRights!.Value.HasFlag(AdministrationRights.UploadVersion)) return Forbid(); } - else if (!AuthenticationContext.PermissionSet.AdministrationRights.Value.HasFlag(AdministrationRights.ChangeVersion)) + else if (!AuthenticationContext.PermissionSet.AdministrationRights!.Value.HasFlag(AdministrationRights.ChangeVersion)) return Forbid(); if (model.NewVersion == null) @@ -379,7 +377,7 @@ public async ValueTask GetLog(string path, CancellationToken canc /// A resulting in the of the request. async ValueTask AttemptInitiateUpdate(Version newVersion, bool attemptingUpload, CancellationToken cancellationToken) { - IFileUploadTicket uploadTicket = attemptingUpload + IFileUploadTicket? uploadTicket = attemptingUpload ? fileTransferService.CreateUpload(FileUploadStreamKind.None) : null; @@ -393,7 +391,7 @@ async ValueTask AttemptInitiateUpdate(Version newVersion, bool at catch { if (attemptingUpload) - await uploadTicket.DisposeAsync(); + await uploadTicket!.DisposeAsync(); throw; } From c63352e04cbcbb7287214f802b94c29aba10cdab Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:21:43 -0500 Subject: [PATCH 373/717] Nullify `ApiController` --- .../Controllers/ApiController.cs | 24 +++++++++---------- .../Extensions/ControllerBaseExtensions.cs | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ApiController.cs b/src/Tgstation.Server.Host/Controllers/ApiController.cs index 561bde364b5..ea8c4c32093 100644 --- a/src/Tgstation.Server.Host/Controllers/ApiController.cs +++ b/src/Tgstation.Server.Host/Controllers/ApiController.cs @@ -28,8 +28,6 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -50,7 +48,7 @@ public abstract class ApiController : ApiControllerBase /// /// The for the operation. /// - protected ApiHeaders ApiHeaders => ApiHeadersProvider.ApiHeaders; + protected ApiHeaders? ApiHeaders => ApiHeadersProvider.ApiHeaders; /// /// The containing value of . @@ -75,7 +73,7 @@ public abstract class ApiController : ApiControllerBase /// /// The for the operation. /// - protected Models.Instance Instance { get; } + protected Models.Instance? Instance { get; } /// /// If are required. @@ -102,13 +100,13 @@ protected ApiController( ApiHeadersProvider = apiHeadersProvider ?? throw new ArgumentNullException(nameof(apiHeadersProvider)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); - Instance = AuthenticationContext?.InstancePermissionSet?.Instance; + Instance = AuthenticationContext.InstancePermissionSet?.Instance; this.requireHeaders = requireHeaders; } /// #pragma warning disable CA1506 // TODO: Decomplexify - protected override async ValueTask HookExecuteAction(Func executeAction, CancellationToken cancellationToken) + protected override async ValueTask HookExecuteAction(Func executeAction, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(executeAction); @@ -116,7 +114,7 @@ protected override async ValueTask HookExecuteAction(Func e if (ApiHeaders == null) { if (requireHeaders) - return HeadersIssue(ApiHeadersProvider.HeadersException); + return HeadersIssue(ApiHeadersProvider.HeadersException!); } var errorCase = await ValidateRequest(cancellationToken); @@ -126,7 +124,7 @@ protected override async ValueTask HookExecuteAction(Func e if (ModelState?.IsValid == false) { var errorMessages = ModelState - .SelectMany(x => x.Value.Errors) + .SelectMany(x => x.Value!.Errors) .Select(x => x.ErrorMessage) // We use RequiredAttributes purely for preventing properties from becoming nullable in the databases @@ -240,8 +238,8 @@ protected ObjectResult RateLimit(RateLimitExceededException rateLimitException) /// /// The for the operation. /// A resulting in an appropriate on validation failure, otherwise. - protected virtual ValueTask ValidateRequest(CancellationToken cancellationToken) - => ValueTask.FromResult(null); + protected virtual ValueTask ValidateRequest(CancellationToken cancellationToken) + => ValueTask.FromResult(null); /// /// Response for missing/Invalid headers. @@ -276,7 +274,7 @@ protected IActionResult HeadersIssue(HeadersException headersException) /// A resulting in the for the operation. protected ValueTask Paginated( Func>> queryGenerator, - Func resultTransformer, + Func? resultTransformer, int? pageQuery, int? pageSizeQuery, CancellationToken cancellationToken) => PaginatedImpl( @@ -324,7 +322,7 @@ protected ValueTask Paginated( /// A resulting in the for the operation. async ValueTask PaginatedImpl( Func>> queryGenerator, - Func resultTransformer, + Func? resultTransformer, int? pageQuery, int? pageSizeQuery, CancellationToken cancellationToken) @@ -344,7 +342,7 @@ async ValueTask PaginatedImpl( var page = pageQuery ?? 1; var paginationResult = await queryGenerator(); - if (paginationResult.EarlyOut != null) + if (!paginationResult.Valid) return paginationResult.EarlyOut; var queriedResults = paginationResult diff --git a/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs b/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs index 9ab3b1cc87e..f74a30913c8 100644 --- a/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs @@ -28,7 +28,7 @@ public static ObjectResult Gone(this ControllerBase controller) /// The . /// The accompanying payload. /// A with the given . - public static ObjectResult StatusCode(this ControllerBase controller, HttpStatusCode statusCode, object errorMessage) + public static ObjectResult StatusCode(this ControllerBase controller, HttpStatusCode statusCode, object? errorMessage) => controller?.StatusCode((int)statusCode, errorMessage) ?? throw new ArgumentNullException(nameof(controller)); } } From 92c4e653e429a5d6b66fb2fa01e003eeefeabdcb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:22:38 -0500 Subject: [PATCH 374/717] Nullify `ApiControllerBase` --- src/Tgstation.Server.Host/Controllers/ApiControllerBase.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ApiControllerBase.cs b/src/Tgstation.Server.Host/Controllers/ApiControllerBase.cs index 8e313397f1c..748dd810966 100644 --- a/src/Tgstation.Server.Host/Controllers/ApiControllerBase.cs +++ b/src/Tgstation.Server.Host/Controllers/ApiControllerBase.cs @@ -8,8 +8,6 @@ using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -39,7 +37,7 @@ public sealed override async Task OnActionExecutionAsync(ActionExecutingContext /// A that should be invoked and its response awaited to continue normal execution of the request. Should NOT be called if this method returns a non- value. /// The for the operation. /// A resulting in an that, if not , is executed. - protected virtual async ValueTask HookExecuteAction(Func executeAction, CancellationToken cancellationToken) + protected virtual async ValueTask HookExecuteAction(Func executeAction, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(executeAction); From d41f143cf8fd3798ac68c91bcf713eb08f7498be Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:25:12 -0500 Subject: [PATCH 375/717] Nullify `ApiRootController` --- .../Controllers/ApiRootController.cs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ApiRootController.cs b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs index 5480c689d21..334eba85a42 100644 --- a/src/Tgstation.Server.Host/Controllers/ApiRootController.cs +++ b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs @@ -27,8 +27,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -215,7 +213,7 @@ public async ValueTask CreateToken(CancellationToken cancellation if (ApiHeaders == null) { Response.Headers.Add(HeaderNames.WWWAuthenticate, new StringValues($"basic realm=\"Create TGS {ApiHeaders.BearerAuthenticationScheme} token\"")); - return HeadersIssue(ApiHeadersProvider.HeadersException); + return HeadersIssue(ApiHeadersProvider.HeadersException!); } if (ApiHeaders.IsTokenAuthentication) @@ -223,12 +221,12 @@ public async ValueTask CreateToken(CancellationToken cancellation var oAuthLogin = ApiHeaders.OAuthProvider.HasValue; - ISystemIdentity systemIdentity = null; + ISystemIdentity? systemIdentity = null; if (!oAuthLogin) try { // trust the system over the database because a user's name can change while still having the same SID - systemIdentity = await systemIdentityFactory.CreateSystemIdentity(ApiHeaders.Username, ApiHeaders.Password, cancellationToken); + systemIdentity = await systemIdentityFactory.CreateSystemIdentity(ApiHeaders.Username!, ApiHeaders.Password!, cancellationToken); } catch (NotImplementedException) { @@ -241,8 +239,8 @@ public async ValueTask CreateToken(CancellationToken cancellation IQueryable query = DatabaseContext.Users.AsQueryable(); if (oAuthLogin) { - var oAuthProvider = ApiHeaders.OAuthProvider.Value; - string externalUserId; + var oAuthProvider = ApiHeaders.OAuthProvider!.Value; + string? externalUserId; try { var validator = oAuthProviders @@ -313,7 +311,7 @@ public async ValueTask CreateToken(CancellationToken cancellation if (!usingSystemIdentity) { // DB User password check and update - if (!isLikelyDbUser || !cryptographySuite.CheckUserPassword(user, ApiHeaders.Password)) + if (!isLikelyDbUser || !cryptographySuite.CheckUserPassword(user, ApiHeaders.Password!)) return Unauthorized(); if (user.PasswordHash != originalHash) { @@ -329,7 +327,7 @@ public async ValueTask CreateToken(CancellationToken cancellation } else { - var usernameMismatch = systemIdentity.Username != user.Name; + var usernameMismatch = systemIdentity!.Username != user.Name; if (isLikelyDbUser || usernameMismatch) { DatabaseContext.Users.Attach(user); @@ -354,7 +352,7 @@ public async ValueTask CreateToken(CancellationToken cancellation } // Now that the bookeeping is done, tell them to fuck off if necessary - if (!user.Enabled.Value) + if (!user.Enabled!.Value) { Logger.LogTrace("Not logging in disabled user {userId}.", user.Id); return Forbid(); @@ -367,7 +365,7 @@ public async ValueTask CreateToken(CancellationToken cancellation var identExpiry = token.ParseJwt().ValidTo; identExpiry += tokenFactory.ValidationParameters.ClockSkew; identExpiry += TimeSpan.FromSeconds(15); - identityCache.CacheSystemIdentity(user, systemIdentity, identExpiry); + identityCache.CacheSystemIdentity(user, systemIdentity!, identExpiry); } Logger.LogDebug("Successfully logged in user {userId}!", user.Id); From 1c3b12f9694334bc14cdf878bc603b58049a62ec Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:27:59 -0500 Subject: [PATCH 376/717] Nullify `BridgeController` --- .../Controllers/BridgeController.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/BridgeController.cs b/src/Tgstation.Server.Host/Controllers/BridgeController.cs index 96c44f5085c..4b1a1fac3e6 100644 --- a/src/Tgstation.Server.Host/Controllers/BridgeController.cs +++ b/src/Tgstation.Server.Host/Controllers/BridgeController.cs @@ -18,8 +18,6 @@ using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -91,7 +89,7 @@ public async ValueTask Process([FromQuery] string data, Cancellat { // Nothing to see here var remoteIP = Request.HttpContext.Connection.RemoteIpAddress; - if (!IPAddress.IsLoopback(remoteIP)) + if (remoteIP == null || !IPAddress.IsLoopback(remoteIP)) { logger.LogTrace("Rejecting remote bridge request from {remoteIP}", remoteIP); return Forbid(); @@ -99,7 +97,7 @@ public async ValueTask Process([FromQuery] string data, Cancellat using (LogContext.PushProperty(SerilogContextHelper.BridgeRequestIterationContextProperty, Interlocked.Increment(ref requestsProcessed))) { - BridgeParameters request; + BridgeParameters? request; try { request = JsonConvert.DeserializeObject(data, DMApiConstants.SerializerSettings); @@ -111,6 +109,13 @@ public async ValueTask Process([FromQuery] string data, Cancellat return BadRequest(); } + if (request == null) + { + if (LogContent) + logger.LogWarning("Error deserializing bridge request: {badJson}", data); + return BadRequest(); + } + if (LogContent) logger.LogTrace("Bridge Request: {json}", data); From 6a8b48ad68fcb9944e9b020bd256779df30ca341 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:33:15 -0500 Subject: [PATCH 377/717] Nullify `ChatController` --- .../Controllers/ChatController.cs | 23 +++++++++---------- .../Controllers/InstanceRequiredController.cs | 5 ++++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ChatController.cs b/src/Tgstation.Server.Host/Controllers/ChatController.cs index 551d03d9435..fc411b460a3 100644 --- a/src/Tgstation.Server.Host/Controllers/ChatController.cs +++ b/src/Tgstation.Server.Host/Controllers/ChatController.cs @@ -25,9 +25,8 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -using Z.EntityFramework.Plus; -#nullable disable +using Z.EntityFramework.Plus; namespace Tgstation.Server.Host.Controllers { @@ -120,7 +119,7 @@ public async ValueTask Create([FromBody] ChatBotCreateRequest mod .Where(x => x.InstanceId == Instance.Id) .CountAsync(cancellationToken); - if (countOfExistingBotsInInstance >= Instance.ChatBotLimit.Value) + if (countOfExistingBotsInInstance >= Instance.ChatBotLimit!.Value) return Conflict(new ErrorMessageResponse(ErrorCode.ChatBotMax)); model.Enabled ??= false; @@ -132,8 +131,8 @@ public async ValueTask Create([FromBody] ChatBotCreateRequest mod Name = model.Name, ConnectionString = model.ConnectionString, Enabled = model.Enabled, - Channels = model.Channels?.Select(x => ConvertApiChatChannel(x, model.Provider.Value)).ToList() ?? new List(), // important that this isn't null - InstanceId = Instance.Id.Value, + Channels = model.Channels?.Select(x => ConvertApiChatChannel(x, model.Provider!.Value)).ToList() ?? new List(), // important that this isn't null + InstanceId = Instance.Id!.Value, Provider = model.Provider, ReconnectionInterval = model.ReconnectionInterval, ChannelLimit = model.ChannelLimit, @@ -151,7 +150,7 @@ public async ValueTask Create([FromBody] ChatBotCreateRequest mod await instance.Chat.ChangeSettings(dbModel, cancellationToken); if (dbModel.Channels.Count > 0) - await instance.Chat.ChangeChannels(dbModel.Id.Value, dbModel.Channels, cancellationToken); + await instance.Chat.ChangeChannels(dbModel.Id!.Value, dbModel.Channels, cancellationToken); } catch { @@ -160,7 +159,7 @@ public async ValueTask Create([FromBody] ChatBotCreateRequest mod // DCTx2: Operations must always run await DatabaseContext.Save(default); - await instance.Chat.DeleteConnection(dbModel.Id.Value, default); + await instance.Chat.DeleteConnection(dbModel.Id!.Value, default); throw; } @@ -297,7 +296,7 @@ public async ValueTask Update([FromBody] ChatBotUpdateRequest mod if (current == default) return this.Gone(); - if ((model.Channels?.Count ?? current.Channels.Count) > (model.ChannelLimit ?? current.ChannelLimit.Value)) + if ((model.Channels?.Count ?? current.Channels.Count) > (model.ChannelLimit ?? current.ChannelLimit!.Value)) { // 400 or 409 depends on if the client sent both var errorMessage = new ErrorMessageResponse(ErrorCode.ChatBotMaxChannels); @@ -343,7 +342,7 @@ bool CheckModified(Expression> expression, ChatBotRi DatabaseContext.ChatChannels.RemoveRange(current.Channels); if (hasChannels) { - var dbChannels = model.Channels.Select(x => ConvertApiChatChannel(x, model.Provider ?? current.Provider.Value)).ToList(); + var dbChannels = model.Channels!.Select(x => ConvertApiChatChannel(x, model.Provider ?? current.Provider!.Value)).ToList(); DatabaseContext.ChatChannels.AddRange(dbChannels); current.Channels = dbChannels; } @@ -360,8 +359,8 @@ bool CheckModified(Expression> expression, ChatBotRi if (anySettingsModified) await chat.ChangeSettings(current, cancellationToken); // have to rebuild the thing first - if ((model.Channels != null || anySettingsModified) && current.Enabled.Value) - await chat.ChangeChannels(current.Id.Value, current.Channels, cancellationToken); + if ((model.Channels != null || anySettingsModified) && current.Enabled!.Value) + await chat.ChangeChannels(current.Id!.Value, current.Channels, cancellationToken); return null; }); @@ -384,7 +383,7 @@ bool CheckModified(Expression> expression, ChatBotRi /// The to validate. /// If the is being created. /// An to respond with or . - IActionResult StandardModelChecks(ChatBotApiBase model, bool forCreation) + IActionResult? StandardModelChecks(ChatBotApiBase model, bool forCreation) { if (model.ReconnectionInterval == 0) throw new InvalidOperationException("RecconnectionInterval cannot be zero!"); diff --git a/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs b/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs index 6ee1fe49632..68dec105043 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs @@ -14,6 +14,11 @@ namespace Tgstation.Server.Host.Controllers /// public abstract class InstanceRequiredController : ComponentInterfacingController { + /// + /// The . + /// + protected new Models.Instance Instance => base.Instance!; + /// /// Initializes a new instance of the class. /// From f4ff59ce1faf70a14bc06413e14d75938b8d74cb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:36:35 -0500 Subject: [PATCH 378/717] Nullify `ComponentInterfacingController` --- .../Controllers/ChatController.cs | 6 ++--- .../ComponentInterfacingController.cs | 25 +++++++++++++------ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ChatController.cs b/src/Tgstation.Server.Host/Controllers/ChatController.cs index fc411b460a3..6b35f19d284 100644 --- a/src/Tgstation.Server.Host/Controllers/ChatController.cs +++ b/src/Tgstation.Server.Host/Controllers/ChatController.cs @@ -141,7 +141,7 @@ public async ValueTask Create([FromBody] ChatBotCreateRequest mod DatabaseContext.ChatBots.Add(dbModel); await DatabaseContext.Save(cancellationToken); - return await WithComponentInstance( + return await WithComponentInstanceNullable( async instance => { try @@ -180,7 +180,7 @@ public async ValueTask Create([FromBody] ChatBotCreateRequest mod [TgsAuthorize(ChatBotRights.Delete)] [ProducesResponseType(204)] public async ValueTask Delete(long id, CancellationToken cancellationToken) - => await WithComponentInstance( + => await WithComponentInstanceNullable( async instance => { await Task.WhenAll( @@ -352,7 +352,7 @@ bool CheckModified(Expression> expression, ChatBotRi await DatabaseContext.Save(cancellationToken); - earlyOut = await WithComponentInstance( + earlyOut = await WithComponentInstanceNullable( async instance => { var chat = instance.Chat; diff --git a/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs b/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs index c830a45d17b..108390890fd 100644 --- a/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs +++ b/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs @@ -10,11 +10,10 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Database; +using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -65,18 +64,18 @@ protected ComponentInterfacingController( } /// - protected override async ValueTask ValidateRequest(CancellationToken cancellationToken) + protected override async ValueTask ValidateRequest(CancellationToken cancellationToken) { if (!useInstanceRequestHeader) return null; - if (!ApiHeaders.InstanceId.HasValue) + if (!ApiHeaders!.InstanceId.HasValue) return BadRequest(new ErrorMessageResponse(ErrorCode.InstanceHeaderRequired)); if (AuthenticationContext.InstancePermissionSet == null) return Forbid(); - if (ValidateInstanceOnlineStatus(Instance)) + if (ValidateInstanceOnlineStatus(Instance!)) await DatabaseContext.Save(cancellationToken); using var instanceReferenceCheck = instanceManager.GetInstanceReference(Instance); @@ -99,7 +98,7 @@ protected bool ValidateInstanceOnlineStatus(Api.Models.Instance metadata) using (var instanceReferenceCheck = instanceManager.GetInstanceReference(metadata)) online = instanceReferenceCheck != null; - if (metadata.Online.Value == online) + if (metadata.Require(x => x.Online) == online) return false; const string OfflineWord = "offline"; @@ -122,11 +121,11 @@ protected bool ValidateInstanceOnlineStatus(Api.Models.Instance metadata) /// The to grab. If , will be used. /// A resulting in the that should be returned. /// The context of should be as small as possible so as to avoid race conditions. This function can return a if the requested instance was offline. - protected async ValueTask WithComponentInstance(Func> action, Models.Instance instance = null) + protected async ValueTask WithComponentInstanceNullable(Func> action, Models.Instance? instance = null) { ArgumentNullException.ThrowIfNull(action); - instance ??= Instance; + instance ??= Instance ?? throw new InvalidOperationException("ComponentInterfacingController has no Instance!"); using var instanceReference = instanceManager.GetInstanceReference(instance); using (LogContext.PushProperty(SerilogContextHelper.InstanceReferenceContextProperty, instanceReference.Uid)) @@ -136,5 +135,15 @@ protected async ValueTask WithComponentInstance(Func + /// Run a given with the relevant . + /// + /// A accepting the and returning a with the . + /// The to grab. If , will be used. + /// A resulting in the that should be returned. + /// The context of should be as small as possible so as to avoid race conditions. This function can return a if the requested instance was offline. + protected async ValueTask WithComponentInstance(Func> action, Models.Instance? instance = null) + => (await WithComponentInstanceNullable(async core => await action(core), instance))!; } } From 38728291fc44af97e2d835d2060988ad5f04718a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:47:02 -0500 Subject: [PATCH 379/717] Nullify `ConfigurationController` --- .../Controllers/ConfigurationController.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs b/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs index 2b95796ef7e..1df1fbc9079 100644 --- a/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs +++ b/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs @@ -19,8 +19,6 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -75,7 +73,7 @@ public ConfigurationController( public async ValueTask Update([FromBody] ConfigurationFileRequest model, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(model); - if (ForbidDueToModeConflicts(model.Path, out var systemIdentity)) + if (ForbidDueToModeConflicts(model.Path!, out var systemIdentity)) return Forbid(); try @@ -166,7 +164,7 @@ public async ValueTask File(string filePath, CancellationToken ca [ProducesResponseType(typeof(ErrorMessageResponse), 409)] [ProducesResponseType(typeof(ErrorMessageResponse), 410)] public ValueTask Directory( - string directoryPath, + string? directoryPath, [FromQuery] int? page, [FromQuery] int? pageSize, CancellationToken cancellationToken) @@ -340,7 +338,7 @@ public async ValueTask DeleteDirectory([FromBody] ConfigurationFi /// The path to validate if any. /// The to use when calling into . /// if a should be returned, otherwise. - bool ForbidDueToModeConflicts(string path, out ISystemIdentity systemIdentityToUse) + bool ForbidDueToModeConflicts(string? path, out ISystemIdentity? systemIdentityToUse) { if (Instance.ConfigurationType == ConfigurationType.Disallowed || (Instance.ConfigurationType == ConfigurationType.SystemIdentityWrite && AuthenticationContext.SystemIdentity == null) From 13563cff64c15a26f77a5c242391fbd260e5089c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 25 Nov 2023 16:47:21 -0500 Subject: [PATCH 380/717] Nullify `ControlPanelController` --- src/Tgstation.Server.Host/Controllers/ControlPanelController.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs b/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs index 1d2d1274b82..08d8f74dad1 100644 --- a/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs +++ b/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs @@ -16,8 +16,6 @@ using Tgstation.Server.Api; using Tgstation.Server.Host.Configuration; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// From 4de500f4286f021aebe5735f7901618d2e650e80 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 26 Nov 2023 17:06:30 -0500 Subject: [PATCH 381/717] More detailed accounting when JobsHubTests fail --- tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index 493e2d1d4f1..d9456c22bcd 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -195,8 +195,8 @@ static DateTimeOffset PerformDBTruncation(DateTimeOffset original) // some instances may be detached, but our cache remains var accountedJobs = allJobs.Count - missableMissedJobs; - var accountedSeenJobs = seenJobs.Where(x => allInstances.Any(i => i.Id.Value == x.Value.InstanceId)).Count(); - Assert.AreEqual(accountedJobs, accountedSeenJobs); + var accountedSeenJobs = seenJobs.Where(x => allInstances.Any(i => i.Id.Value == x.Value.InstanceId)).ToList(); + Assert.AreEqual(accountedJobs, accountedSeenJobs.Count, $"Mismatch in seen jobs:{Environment.NewLine}{String.Join(Environment.NewLine, allJobs.Where(x => !seenJobs.Any(y => y.Key == x.Id.Value)).Select(x => $"- I:{x.InstanceId}|JID:{x.Id}|JC:{x.JobCode}|Desc:{x.Description}"))}"); Assert.IsTrue(accountedJobs <= seenJobs.Count); Assert.AreNotEqual(0, permlessSeenJobs.Count); Assert.IsTrue(permlessSeenJobs.Count < seenJobs.Count); From 38d84c5a2e9452df25a138be189806bc95cb378a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 26 Nov 2023 17:47:49 -0500 Subject: [PATCH 382/717] More workaround for process read hangs --- src/Tgstation.Server.Host/System/Process.cs | 2 +- src/Tgstation.Server.Host/System/ProcessExecutor.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/System/Process.cs b/src/Tgstation.Server.Host/System/Process.cs index 003f3b12e4a..da67c8f0e89 100644 --- a/src/Tgstation.Server.Host/System/Process.cs +++ b/src/Tgstation.Server.Host/System/Process.cs @@ -153,7 +153,7 @@ public async ValueTask GetCombinedOutput(CancellationToken cancellationT if (handle.HasExited) { handle.WaitForExit(); - await Task.WhenAny(readTask, asyncDelayer.Delay(TimeSpan.FromSeconds(10), cancellationToken)); + await Task.WhenAny(readTask, asyncDelayer.Delay(TimeSpan.FromSeconds(30), cancellationToken)); if (!readTask.IsCompleted) { diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index abe50636843..088cd8325b3 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -250,7 +250,7 @@ async Task GetNextLine() errorReadTask = stdErrHandle.ReadLineAsync(disposeToken).AsTask(); var completedTask = await Task.WhenAny(outputReadTask ?? errorReadTask, errorReadTask ?? outputReadTask); - var line = await completedTask; + var line = await completedTask.WaitAsync(disposeToken); if (completedTask == outputReadTask) { outputReadTask = null; From f34a5342768f40cc448b4526b997464d65d4d27b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 21 Nov 2023 08:33:33 -0500 Subject: [PATCH 383/717] Update Postgres EFCore connector --- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 9890be89d04..5be73fa4ee7 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -95,7 +95,7 @@ - + From 18fc529c37539d66d3af1f6436c507416268a4ef Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 16:23:41 -0500 Subject: [PATCH 384/717] Fix a race condition that caused settings changes to not return API responses with `SoftRestart = true` --- .../Components/Watchdog/IWatchdog.cs | 4 ++-- .../Components/Watchdog/WatchdogBase.cs | 8 +++++--- .../Controllers/DreamDaemonController.cs | 13 +++++++++---- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs index a54cde8e838..7600dc9a366 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs @@ -62,8 +62,8 @@ public interface IWatchdog : IComponentService, IAsyncDisposable, IEventConsumer /// /// The new . May be modified. /// The for the operation. - /// A representing the running operation. - ValueTask ChangeSettings(DreamDaemonLaunchParameters launchParameters, CancellationToken cancellationToken); + /// A resulting in if a reboot is required, otherwise. + ValueTask ChangeSettings(DreamDaemonLaunchParameters launchParameters, CancellationToken cancellationToken); /// /// Restarts the watchdog. diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index 33b5ca07201..33961aa1f6e 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -267,18 +267,20 @@ public async ValueTask DisposeAsync() } /// - public async ValueTask ChangeSettings(DreamDaemonLaunchParameters launchParameters, CancellationToken cancellationToken) + public async ValueTask ChangeSettings(DreamDaemonLaunchParameters launchParameters, CancellationToken cancellationToken) { using (await SemaphoreSlimContext.Lock(synchronizationSemaphore, cancellationToken)) { bool match = launchParameters.CanApplyWithoutReboot(ActiveLaunchParameters); ActiveLaunchParameters = launchParameters; - if (match || Status == WatchdogStatus.Offline) - return; + if (match || Status == WatchdogStatus.Offline || Status == WatchdogStatus.DelayedRestart) + return false; var oldTcs = Interlocked.Exchange(ref activeParametersUpdated, new TaskCompletionSource()); oldTcs.SetResult(); } + + return true; } /// diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index 5a3ff51f0e5..ca84dac467f 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -106,7 +106,7 @@ await jobManager.RegisterOperation( [TgsAuthorize(DreamDaemonRights.ReadMetadata | DreamDaemonRights.ReadRevision)] [ProducesResponseType(typeof(DreamDaemonResponse), 200)] [ProducesResponseType(typeof(ErrorMessageResponse), 410)] - public ValueTask Read(CancellationToken cancellationToken) => ReadImpl(null, cancellationToken); + public ValueTask Read(CancellationToken cancellationToken) => ReadImpl(null, false, cancellationToken); /// /// Stops the Watchdog if it's running. @@ -231,7 +231,7 @@ bool CheckModified(Expression(Expression. /// /// The to operate on if any. + /// If there was a settings change made that forced a switch to . /// The for the operation. /// A resulting in the of the operation. - ValueTask ReadImpl(DreamDaemonSettings settings, CancellationToken cancellationToken) + ValueTask ReadImpl(DreamDaemonSettings settings, bool knownForcedReboot, CancellationToken cancellationToken) => WithComponentInstance(async instance => { var dd = instance.Watchdog; @@ -360,6 +361,10 @@ ValueTask ReadImpl(DreamDaemonSettings settings, CancellationToke result.Visibility = settings.Visibility.Value; result.SoftRestart = rstate == RebootState.Restart; result.SoftShutdown = rstate == RebootState.Shutdown; + + if (rstate == RebootState.Normal && knownForcedReboot) + result.SoftRestart = true; + result.StartupTimeout = settings.StartupTimeout.Value; result.HealthCheckSeconds = settings.HealthCheckSeconds.Value; result.DumpOnHealthCheckRestart = settings.DumpOnHealthCheckRestart.Value; From 0973174c10b8f3c657ae24fc57bf4e583f25337c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 16:24:48 -0500 Subject: [PATCH 385/717] Improve live test runtimes Workstation improvement of 10.2 to 6.4 minutes. --- tests/DMAPI/LongRunning/Test.dm | 18 ++- .../Live/Instance/ChatTest.cs | 1 + .../Live/Instance/DeploymentTest.cs | 1 + .../Live/Instance/InstanceTest.cs | 19 +-- .../Live/Instance/JobsRequiredTest.cs | 104 ++++++++------ .../Live/Instance/WatchdogTest.cs | 133 ++++++++++-------- .../Live/TestLiveServer.cs | 20 +-- 7 files changed, 172 insertions(+), 124 deletions(-) diff --git a/tests/DMAPI/LongRunning/Test.dm b/tests/DMAPI/LongRunning/Test.dm index 0bff755db9b..90164c7e800 100644 --- a/tests/DMAPI/LongRunning/Test.dm +++ b/tests/DMAPI/LongRunning/Test.dm @@ -6,9 +6,11 @@ log << "Initial value of sleep_offline: [sleep_offline]" sleep_offline = FALSE - // Intentionally slow down startup for testing purposes - for(var/i in 1 to 10000000) - dab() + if(params["slow_start"]) + // Intentionally slow down startup for health check testing purposes + for(var/i in 1 to 10000000) + dab() + TgsNew(new /datum/tgs_event_handler/impl, TGS_SECURITY_SAFE) var/sec = TgsSecurityLevel() @@ -189,7 +191,7 @@ var/run_bridge_test var/its_sad = data["im_out_of_memes"] if(its_sad) TestLegacyBridge() - return "yeah gimmie a sec" + return "all gucci" TgsChatBroadcast(new /datum/tgs_message_content("Received non-tgs topic: `[T]`")) @@ -252,9 +254,9 @@ var/received_health_check = FALSE /proc/RebootAsync() set waitfor = FALSE - world.TgsChatBroadcast(new /datum/tgs_message_content("Rebooting after 3 seconds")); + world.TgsChatBroadcast(new /datum/tgs_message_content("Rebooting after 1 seconds")); world.log << "About to sleep. sleep_offline: [world.sleep_offline]" - sleep(30) + sleep(10) world.log << "Done sleep, calling Reboot" world.Reboot() @@ -362,10 +364,6 @@ var/suppress_bridge_spam = FALSE api.access_identifier = old_ai /proc/TestLegacyBridge() - set waitfor = FALSE - - sleep(10) - var/datum/tgs_api/v5/api = TGS_READ_GLOBAL(tgs) if(api.interop_version.suite != 5) FailTest("Legacy bridge test not required anymore?") diff --git a/tests/Tgstation.Server.Tests/Live/Instance/ChatTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/ChatTest.cs index 0963b72b4fb..abb699815e4 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/ChatTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/ChatTest.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; using Tgstation.Server.Api.Models; diff --git a/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs index 8b5fab58c91..d0d074e6e88 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs @@ -1,6 +1,7 @@ using System; using System.Threading; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; using Tgstation.Server.Api.Models; diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 255a2e8a83a..fc5177e3558 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -45,11 +45,11 @@ public async Task RunTests( CancellationToken cancellationToken) { var testVersion = await EngineTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); - var engineTest = new EngineTest(instanceClient.Engine, instanceClient.Jobs, fileDownloader, instanceClient.Metadata, testVersion.Engine.Value); - var chatTest = new ChatTest(instanceClient.ChatBots, instanceManagerClient, instanceClient.Jobs, instanceClient.Metadata); + await using var engineTest = new EngineTest(instanceClient.Engine, instanceClient.Jobs, fileDownloader, instanceClient.Metadata, testVersion.Engine.Value); + await using var chatTest = new ChatTest(instanceClient.ChatBots, instanceManagerClient, instanceClient.Jobs, instanceClient.Metadata); var configTest = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata); - var repoTest = new RepositoryTest(instanceClient.Repository, instanceClient.Jobs); - var dmTest = new DeploymentTest(instanceClient, instanceClient.Jobs, dmPort, ddPort, lowPrioDeployment, testVersion.Engine.Value); + await using var repoTest = new RepositoryTest(instanceClient.Repository, instanceClient.Jobs); + await using var dmTest = new DeploymentTest(instanceClient, instanceClient.Jobs, dmPort, ddPort, lowPrioDeployment, testVersion.Engine.Value); var byondTask = engineTest.Run(cancellationToken, out var firstInstall); var chatTask = chatTest.RunPreWatchdog(cancellationToken); @@ -66,15 +66,15 @@ public async Task RunTests( await configTest.SetupDMApiTests(true, cancellationToken); await byondTask; - await new WatchdogTest( + await using var wdt = new WatchdogTest( testVersion, instanceClient, instanceManager, serverPort, highPrioDD, ddPort, - usingBasicWatchdog) - .Run(cancellationToken); + usingBasicWatchdog); + await wdt.Run(cancellationToken); } public static async ValueTask DownloadEngineVersion( @@ -197,7 +197,7 @@ public async Task RunCompatTests( ReconnectionInterval = 1, }, cancellationToken); - var jrt = new JobsRequiredTest(instanceClient.Jobs); + await using var jrt = new JobsRequiredTest(instanceClient.Jobs); EngineInstallResponse installJob2; await using (var stableBytesMs = await TestingUtils.ExtractMemoryStreamFromInstallationData( @@ -257,7 +257,8 @@ await instanceClient.Repository.Update(new RepositoryUpdateRequest await configSetupTask; - await new WatchdogTest(compatVersion, instanceClient, instanceManager, serverPort, highPrioDD, ddPort, usingBasicWatchdog).Run(cancellationToken); + await using var wdt = new WatchdogTest(compatVersion, instanceClient, instanceManager, serverPort, highPrioDD, ddPort, usingBasicWatchdog); + await wdt.Run(cancellationToken); await instanceManagerClient.Update(new InstanceUpdateRequest { diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsRequiredTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsRequiredTest.cs index bfe8c98d825..e7c7cb610c5 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsRequiredTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsRequiredTest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -13,16 +14,65 @@ namespace Tgstation.Server.Tests.Live.Instance { - class JobsRequiredTest + class JobsRequiredTest : IAsyncDisposable { protected IJobsClient JobsClient { get; } readonly IApiClient apiClient; + IAsyncDisposable hubConnection; + readonly Task hubConnectionTask; + readonly CancellationTokenSource cancellationTokenSource; + + readonly ConcurrentDictionary> registry; + public JobsRequiredTest(IJobsClient jobsClient) { JobsClient = jobsClient ?? throw new ArgumentNullException(nameof(jobsClient)); apiClient = (IApiClient)jobsClient.GetType().GetProperty("ApiClient", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(jobsClient); + registry = new ConcurrentDictionary>(); + + cancellationTokenSource = new CancellationTokenSource(); + hubConnectionTask = CreateHubConnection(); + } + + async Task CreateHubConnection() + { + var receiver = new JobReceiver + { + Callback = job => Register(job), + }; + + hubConnection = await apiClient.CreateHubConnection(receiver, null, null, cancellationTokenSource.Token); + } + + public async ValueTask DisposeAsync() + { + cancellationTokenSource.Cancel(); + cancellationTokenSource.Dispose(); + await hubConnectionTask; + if (hubConnection != null) + await hubConnection.DisposeAsync(); + } + + Task Register(JobResponse updatedJob) + { + var tcs = registry.AddOrUpdate(updatedJob.Id.Value, + _ => + { + var tcs = new TaskCompletionSource(); + if (updatedJob.StoppedAt.HasValue) + tcs.SetResult(updatedJob); + return tcs; + }, + (_, oldTcs) => + { + if (updatedJob.StoppedAt.HasValue) + oldTcs.TrySetResult(updatedJob); + return oldTcs; + }); + + return tcs.Task; } class JobReceiver : IJobsHub @@ -42,47 +92,21 @@ public async Task WaitForJob(JobResponse originalJob, int timeout, Assert.IsNotNull(originalJob.JobCode); var job = originalJob; + var registryTask = Register(job); + await Task.WhenAny( + registryTask, + Task.Delay(TimeSpan.FromSeconds(timeout), cancellationToken)); + + if (!registryTask.IsCompleted) + // one last get in case SignalR dropped the ball + job = await JobsClient.GetId(job, cancellationToken); + else + job = await registryTask; + if (!job.StoppedAt.HasValue) { - var tcs = new TaskCompletionSource(); - var receiver = new JobReceiver - { - Callback = updatedJob => - { - if (updatedJob.Id != job.Id) - return; - - job = updatedJob; - if (updatedJob.StoppedAt.HasValue) - tcs.TrySetResult(); - }, - }; - - JobResponse firstCheck; - await using (var hubConnection = await apiClient.CreateHubConnection(receiver, null, null, cancellationToken)) - { - // initial GET after connecting - firstCheck = await JobsClient.GetId(job, cancellationToken); - if (!firstCheck.StoppedAt.HasValue) - { - firstCheck = null; - await Task.WhenAny( - tcs.Task, - Task.Delay(TimeSpan.FromSeconds(timeout), cancellationToken)); - } - } - - if (firstCheck != null) - job = firstCheck; - else if (!job.StoppedAt.HasValue) - // one last get in case SignalR dropped the ball - job = await JobsClient.GetId(job, cancellationToken); - - if (!job.StoppedAt.HasValue) - { - await JobsClient.Cancel(job, cancellationToken); - Assert.Fail($"Job ID {job.Id} \"{job.Description}\" timed out!"); - } + await JobsClient.Cancel(job, cancellationToken); + Assert.Fail($"Job ID {job.Id} \"{job.Description}\" timed out!"); } if (expectFailure.HasValue && expectFailure.Value ^ job.ExceptionDetails != null) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index bcde5714ff2..a5e6f12187f 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -1,6 +1,5 @@ using Byond.TopicSender; -using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -68,6 +67,7 @@ sealed class WatchdogTest : JobsRequiredTest readonly bool watchdogRestartsProcess; bool ranTimeoutTest = false; + const string BaseAdditionalParameters = "expect_chat_channels=1&expect_static_files=1"; public WatchdogTest(EngineVersion testVersion, IInstanceClient instanceClient, InstanceManager instanceManager, ushort serverPort, bool highPrioDD, ushort ddPort, bool watchdogRestartsProcess) : base(instanceClient.Jobs) @@ -88,8 +88,20 @@ public WatchdogTest(EngineVersion testVersion, IInstanceClient instanceClient, I DisconnectTimeout = TimeSpan.FromSeconds(30) }, loggerFactory.CreateLogger($"WatchdogTest.TopicClient.{instanceClient.Metadata.Name}")); } - public async Task Run(CancellationToken cancellationToken) + { + try + { + await RunInt(cancellationToken); + } + catch + { + System.Console.WriteLine($"WATCHDOG TEST FAILING INSTANCE ID {instanceClient.Metadata.Id.Value}"); + throw; + } + } + + async Task RunInt(CancellationToken cancellationToken) { System.Console.WriteLine($"TEST: START WATCHDOG TESTS {instanceClient.Metadata.Name}"); @@ -125,7 +137,7 @@ await Task.WhenAll( Port = ddPort, MapThreads = 2, LogOutput = false, - AdditionalParameters = "expect_chat_channels=1&expect_static_files=1" + AdditionalParameters = BaseAdditionalParameters }, cancellationToken).AsTask(), CheckByondVersions(), ApiAssert.ThrowsException(() => instanceClient.DreamDaemon.Update(new DreamDaemonRequest @@ -176,7 +188,6 @@ async ValueTask RunTest(bool useTrusted) var ddUpdateTask = instanceClient.DreamDaemon.Update(new DreamDaemonRequest { SecurityLevel = useTrusted ? DreamDaemonSecurity.Trusted : DreamDaemonSecurity.Safe, - AdditionalParameters = "expect_chat_channels=1&expect_static_files=1", }, cancellationToken); var currentStatus = await DeployTestDme("long_running_test_rooted", DreamDaemonSecurity.Trusted, true, cancellationToken); await ddUpdateTask; @@ -294,24 +305,25 @@ await ApiAssert.ThrowsException(() => in async ValueTask RegressionTest1550(CancellationToken cancellationToken) { + // Previous test, StartAndLeaveRunning, has SoftRestart set. We don't want that. + var restartJob = await instanceClient.DreamDaemon.Restart(cancellationToken); + await WaitForJob(restartJob, 10, false, null, cancellationToken); + // we need to cycle deployments twice because TGS holds the initial deployment var currentStatus = await DeployTestDme("LongRunning/long_running_test", DreamDaemonSecurity.Trusted, true, cancellationToken); Assert.AreEqual(WatchdogStatus.Online, currentStatus.Status); Assert.IsNotNull(currentStatus.StagedCompileJob); - ValidateSessionId(currentStatus, false); + ValidateSessionId(currentStatus, true); var expectedStaged = currentStatus.StagedCompileJob; Assert.AreNotEqual(expectedStaged.Id, currentStatus.ActiveCompileJob.Id); - Assert.AreEqual(watchdogRestartsProcess, currentStatus.SoftRestart); - Assert.IsFalse(currentStatus.SoftShutdown.Value); + Assert.IsFalse(currentStatus.SoftShutdown); currentStatus = await TellWorldToReboot(true, cancellationToken); - ValidateSessionId(currentStatus, watchdogRestartsProcess); + ValidateSessionId(currentStatus, true); Assert.AreEqual(expectedStaged.Id, currentStatus.ActiveCompileJob.Id); - await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken); - var topicRequestResult = await topicClient.SendTopic( IPAddress.Loopback, $"shadow_wizard_money_gang=1", @@ -322,6 +334,7 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) Assert.AreEqual("we love casting spells", topicRequestResult.StringData); currentStatus = await DeployTestDme("LongRunning/long_running_test", DreamDaemonSecurity.Trusted, true, cancellationToken); + Assert.AreEqual(watchdogRestartsProcess, currentStatus.SoftRestart); ValidateSessionId(currentStatus, false); Assert.AreEqual(WatchdogStatus.Online, currentStatus.Status); @@ -511,11 +524,8 @@ async Task DumpTests(CancellationToken cancellationToken) Assert.IsTrue(job.ErrorCode == ErrorCode.GameServerOffline || job.ErrorCode == ErrorCode.GCoreFailure, $"{job.ErrorCode}: {job.ExceptionDetails}"); - await Task.Delay(TimeSpan.FromSeconds(20), cancellationToken); - - var ddStatus = await instanceClient.DreamDaemon.Read(cancellationToken); - ValidateSessionId(ddStatus, true); - Assert.AreEqual(WatchdogStatus.Online, ddStatus.Status.Value); + var restartJob2 = await instanceClient.DreamDaemon.Restart(cancellationToken); + await WaitForJob(restartJob2, 20, false, null, cancellationToken); } async Task TestDMApiFreeDeploy(CancellationToken cancellationToken) @@ -612,7 +622,7 @@ async Task RunBasicTest(CancellationToken cancellationToken) Assert.AreEqual(false, daemonStatus.SoftRestart); Assert.AreEqual(false, daemonStatus.SoftShutdown); - await GracefulWatchdogShutdown(60, cancellationToken); + await GracefulWatchdogShutdown(cancellationToken); daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.AreEqual(WatchdogStatus.Offline, daemonStatus.Status.Value); @@ -691,20 +701,15 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke { System.Console.WriteLine("TEST: WATCHDOG HEALTH CHECK TEST"); - // Check reverse mapping - var status = await instanceClient.DreamDaemon.Update(new DreamDaemonRequest - { - DumpOnHealthCheckRestart = !checkDump, - }, cancellationToken); - // enable health checks - status = await instanceClient.DreamDaemon.Update(new DreamDaemonRequest + var status = await instanceClient.DreamDaemon.Update(new DreamDaemonRequest { HealthCheckSeconds = 1, DumpOnHealthCheckRestart = checkDump, }, cancellationToken); Assert.AreEqual(checkDump, status.DumpOnHealthCheckRestart); + Assert.AreEqual(1U, status.HealthCheckSeconds.Value); var startJob = await StartDD(cancellationToken); @@ -731,7 +736,7 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke .GetProcess(ddProc.Id); // Ensure it's responding to health checks - await Task.WhenAny(Task.Delay(20000, cancellationToken), ourProcessHandler.Lifetime); + await Task.WhenAny(Task.Delay(6000, cancellationToken), ourProcessHandler.Lifetime); Assert.IsFalse(ddProc.HasExited); // check DD agrees @@ -744,7 +749,7 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke Assert.IsNotNull(topicRequestResult); Assert.AreEqual(TopicResponseType.StringResponse, topicRequestResult.ResponseType); Assert.IsNotNull(topicRequestResult.StringData); - Assert.AreEqual(topicRequestResult.StringData, "received health check"); + Assert.AreEqual("received health check", topicRequestResult.StringData); var ddStatus = await instanceClient.DreamDaemon.Update(new DreamDaemonRequest { @@ -755,11 +760,11 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke ourProcessHandler.Suspend(); await Task.WhenAny(ourProcessHandler.Lifetime, Task.Delay(TimeSpan.FromMinutes(1), cancellationToken)); + Assert.IsTrue(ourProcessHandler.Lifetime.IsCompleted); - var timeout = 60; + var timeout = 20; do { - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); ddStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.AreEqual(1U, ddStatus.HealthCheckSeconds.Value); if (ddStatus.Status.Value == WatchdogStatus.Offline) @@ -770,6 +775,8 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke if (--timeout == 0) Assert.Fail("DreamDaemon didn't shutdown within the timeout!"); + + await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken); } while (timeout > 0); @@ -816,7 +823,6 @@ async Task StartDD(CancellationToken cancellationToken) throw; } } - await Task.Delay(TimeSpan.FromSeconds(3), cts.Token); return await instanceClient.DreamDaemon.Start(cancellationToken); } @@ -855,7 +861,7 @@ async Task WhiteBoxValidateBridgeRequestLimitAndTestChunking(CancellationToken c BridgeController.LogContent = true; // Time for DD to revert the bridge access identifier change - await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken); + await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); } async Task ValidateTopicLimits(CancellationToken cancellationToken) @@ -1249,15 +1255,18 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken public async Task StartAndLeaveRunning(CancellationToken cancellationToken) { System.Console.WriteLine("TEST: WATCHDOG STARTING ENDLESS"); - await DeployTestDme("LongRunning/long_running_test", DreamDaemonSecurity.Trusted, true, cancellationToken); - var startJob = await StartDD(cancellationToken); await WaitForJob(startJob, 40, false, null, cancellationToken); - var daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); + var daemonStatus = await instanceClient.DreamDaemon.Update(new DreamDaemonRequest + { + AdditionalParameters = "slow_start=1", + }, + cancellationToken); - Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value); + Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status); + Assert.IsTrue(daemonStatus.SoftRestart); CheckDDPriority(); Assert.AreEqual(ddPort, daemonStatus.CurrentPort); @@ -1265,6 +1274,9 @@ public async Task StartAndLeaveRunning(CancellationToken cancellationToken) bool firstTime = true; do { + if(!firstTime) + Assert.IsFalse(daemonStatus.SoftRestart); + ValidateSessionId(daemonStatus, true); KillDD(firstTime); firstTime = false; @@ -1272,7 +1284,7 @@ public async Task StartAndLeaveRunning(CancellationToken cancellationToken) daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); } while (daemonStatus.Status == WatchdogStatus.Online); - Assert.AreEqual(WatchdogStatus.Restoring, daemonStatus.Status.Value); + Assert.AreEqual(WatchdogStatus.Restoring, daemonStatus.Status); // Kill it again do @@ -1281,13 +1293,18 @@ public async Task StartAndLeaveRunning(CancellationToken cancellationToken) daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); } while (daemonStatus.Status == WatchdogStatus.Online || daemonStatus.Status == WatchdogStatus.Restoring); - Assert.AreEqual(WatchdogStatus.DelayedRestart, daemonStatus.Status.Value); + Assert.AreEqual(WatchdogStatus.DelayedRestart, daemonStatus.Status); await Task.Delay(TimeSpan.FromSeconds(15), cancellationToken); - daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); + daemonStatus = await instanceClient.DreamDaemon.Update(new DreamDaemonRequest + { + AdditionalParameters = String.Empty, + }, + cancellationToken); ValidateSessionId(daemonStatus, true); - Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value); + Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status); + Assert.IsTrue(daemonStatus.SoftRestart); await CheckDMApiFail(daemonStatus.ActiveCompileJob, cancellationToken); } @@ -1305,12 +1322,12 @@ bool KillDD(bool require) } public Task TellWorldToReboot(bool waitForOnlineIfRestoring, CancellationToken cancellationToken) - => TellWorldToReboot2(instanceClient, topicClient, FindTopicPort(), waitForOnlineIfRestoring ? true : testVersion.Engine.Value == EngineType.OpenDream, cancellationToken); + => TellWorldToReboot2(instanceClient, topicClient, FindTopicPort(), waitForOnlineIfRestoring || testVersion.Engine.Value == EngineType.OpenDream, cancellationToken); public static async Task TellWorldToReboot2(IInstanceClient instanceClient, ITopicClient topicClient, ushort topicPort, bool waitForOnlineIfRestoring, CancellationToken cancellationToken) { var daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.IsNotNull(daemonStatus.StagedCompileJob); - var initialCompileJob = daemonStatus.ActiveCompileJob; + var initialSession = daemonStatus.ActiveCompileJob; System.Console.WriteLine("TEST: Sending world reboot topic..."); @@ -1328,11 +1345,9 @@ public static async Task TellWorldToReboot2(IInstanceClient await Task.Delay(TimeSpan.FromSeconds(1), tempToken); daemonStatus = await instanceClient.DreamDaemon.Read(tempToken); } - while (initialCompileJob.Id == daemonStatus.ActiveCompileJob.Id); + while (initialSession.Id == daemonStatus.ActiveCompileJob.Id); } - await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken); - if (waitForOnlineIfRestoring && daemonStatus.Status == WatchdogStatus.Restoring) { do @@ -1353,7 +1368,7 @@ async Task DeployTestDme(string dmeName, DreamDaemonSecurit ApiValidationSecurityLevel = deploymentSecurity, ProjectName = dmeName.Contains("rooted") ? dmeName : $"tests/DMAPI/{dmeName}", RequireDMApiValidation = requireApi, - Timeout = TimeSpan.FromMilliseconds(1), + Timeout = !ranTimeoutTest ? TimeSpan.FromMilliseconds(1) : TimeSpan.FromMinutes(5), }, cancellationToken); JobResponse compileJobJob; @@ -1366,29 +1381,33 @@ async Task DeployTestDme(string dmeName, DreamDaemonSecurit compileJobJob = await instanceClient.DreamMaker.Compile(cancellationToken); await WaitForJob(compileJobJob, 90, true, ErrorCode.DeploymentTimeout, cancellationToken); + + await instanceClient.DreamMaker.Update(new DreamMakerRequest + { + Timeout = TimeSpan.FromMinutes(5), + }, cancellationToken); ranTimeoutTest = true; } - await instanceClient.DreamMaker.Update(new DreamMakerRequest - { - Timeout = TimeSpan.FromMinutes(5), - }, cancellationToken); - compileJobJob = await instanceClient.DreamMaker.Compile(cancellationToken); await WaitForJob(compileJobJob, 90, false, null, cancellationToken); + // annoying but, with signalR instant job updates, this running task can get queued before the task that processes the watchdog's monitor activation + for (var i = 0; i < 10; ++i) + await Task.Yield(); + var ddInfo = await instanceClient.DreamDaemon.Read(cancellationToken); + var targetJob = ddInfo.StagedCompileJob ?? ddInfo.ActiveCompileJob; + Assert.IsNotNull(targetJob); if (requireApi) - { - var targetJob = ddInfo.StagedCompileJob ?? ddInfo.ActiveCompileJob; - Assert.IsNotNull(targetJob); Assert.IsNotNull(targetJob.DMApiVersion); - } + else + Assert.IsNull(targetJob.DMApiVersion); return ddInfo; } - async Task GracefulWatchdogShutdown(uint timeout, CancellationToken cancellationToken) + async Task GracefulWatchdogShutdown(CancellationToken cancellationToken) { await instanceClient.DreamDaemon.Update(new DreamDaemonRequest { @@ -1398,9 +1417,10 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest var newStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.IsTrue(newStatus.SoftShutdown.Value || newStatus.Status.Value == WatchdogStatus.Offline); + var timeout = 20; do { - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); + await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken); var ddStatus = await instanceClient.DreamDaemon.Read(cancellationToken); if (ddStatus.Status.Value == WatchdogStatus.Offline) break; @@ -1446,9 +1466,10 @@ async Task CheckDMApiFail(CompileJobResponse compileJob, CancellationToken cance async ValueTask TestLegacyBridgeEndpoint(CancellationToken cancellationToken) { + System.Console.WriteLine("TEST: TestLegacyBridgeEndpoint"); var result = await topicClient.SendTopic(IPAddress.Loopback, "im_out_of_memes=1", FindTopicPort(), cancellationToken); - Assert.AreEqual("yeah gimmie a sec", result.StringData); - await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken); + Assert.IsNotNull(result); + Assert.AreEqual("all gucci", result.StringData); await CheckDMApiFail((await instanceClient.DreamDaemon.Read(cancellationToken)).ActiveCompileJob, cancellationToken); } } diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 14b26d8ec85..a419fc648c1 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1049,7 +1049,7 @@ async ValueTask TestTgstation(bool interactive) var ioManager = new Host.IO.DefaultIOManager(); var repoPath = ioManager.ConcatPath(instance.Path, "Repository"); - var jobsTest = new JobsRequiredTest(instanceClient.Jobs); + await using var jobsTest = new JobsRequiredTest(instanceClient.Jobs); var postWriteHandler = (Host.IO.IPostWriteHandler)(new PlatformIdentifier().IsWindows ? new Host.IO.WindowsPostWriteHandler() : new Host.IO.PosixPostWriteHandler(loggerFactory.CreateLogger())); @@ -1590,7 +1590,7 @@ await FailFast( .ToList(); } - var jrt = new JobsRequiredTest(instanceClient.Jobs); + await using var jrt = new JobsRequiredTest(instanceClient.Jobs); foreach (var job in jobs) { Assert.IsTrue(job.StartedAt.Value >= preStartupTime); @@ -1660,11 +1660,11 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) .ToList(); } - var jrt = new JobsRequiredTest(instanceClient.Jobs); + await using var jrt = new JobsRequiredTest(instanceClient.Jobs); foreach (var job in jobs) { Assert.IsTrue(job.StartedAt.Value >= preStartupTime); - await jrt.WaitForJob(job, 140, job.Description.Contains("Reconnect chat bot") ? null : false, null, cancellationToken); + await jrt.WaitForJob(job, 140, job.JobCode == JobCode.ReconnectChatBot ? null : false, null, cancellationToken); } } @@ -1684,7 +1684,7 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value); var compileJob = await instanceClient.DreamMaker.Compile(cancellationToken); - var wdt = new WatchdogTest(edgeVersion, instanceClient, GetInstanceManager(), (ushort)server.ApiUrl.Port, server.HighPriorityDreamDaemon, mainDDPort, server.UsingBasicWatchdog); + await using var wdt = new WatchdogTest(edgeVersion, instanceClient, GetInstanceManager(), (ushort)server.ApiUrl.Port, server.HighPriorityDreamDaemon, mainDDPort, server.UsingBasicWatchdog); await wdt.WaitForJob(compileJob, 30, false, null, cancellationToken); dd = await instanceClient.DreamDaemon.Read(cancellationToken); @@ -1727,13 +1727,15 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest Assert.AreEqual(WatchdogStatus.Online, currentDD.Status); Assert.AreEqual(expectedStaged, currentDD.StagedCompileJob.Job.Id.Value); - var wdt = new WatchdogTest(edgeVersion, instanceClient, GetInstanceManager(), (ushort)server.ApiUrl.Port, server.HighPriorityDreamDaemon, mainDDPort, server.UsingBasicWatchdog); - currentDD = await wdt.TellWorldToReboot(true, cancellationToken); + await using var wdt = new WatchdogTest(edgeVersion, instanceClient, GetInstanceManager(), (ushort)server.ApiUrl.Port, server.HighPriorityDreamDaemon, mainDDPort, server.UsingBasicWatchdog); + currentDD = await wdt.TellWorldToReboot(false, cancellationToken); Assert.AreEqual(expectedStaged, currentDD.ActiveCompileJob.Job.Id.Value); Assert.IsNull(currentDD.StagedCompileJob); - var repoTest = new RepositoryTest(instanceClient.Repository, instanceClient.Jobs).RunPostTest(cancellationToken); - await new ChatTest(instanceClient.ChatBots, adminClient.Instances, instanceClient.Jobs, instance).RunPostTest(cancellationToken); + await using var repoTestObj = new RepositoryTest(instanceClient.Repository, instanceClient.Jobs); + var repoTest = repoTestObj.RunPostTest(cancellationToken); + await using var chatTestObj = new ChatTest(instanceClient.ChatBots, adminClient.Instances, instanceClient.Jobs, instance); + await chatTestObj.RunPostTest(cancellationToken); await repoTest; await DummyChatProvider.RandomDisconnections(false, cancellationToken); From 02c27eb52da9e65bd42f079f4cf36345d32b8c66 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 23 Nov 2023 18:01:40 -0500 Subject: [PATCH 386/717] Probably fix shutdown delay condition with sessions --- .../Components/Chat/ChatTrackingContext.cs | 2 +- .../Components/Session/SessionController.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs b/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs index 369ccdeeebe..03c9ee2e542 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs @@ -16,7 +16,7 @@ sealed class ChatTrackingContext : IChatTrackingContext /// public bool Active { - get => active; + get => active && onDispose != null; set { if (active == value) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index d3feab14a6b..9094cdf5273 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -337,9 +337,8 @@ public async ValueTask DisposeAsync() Logger.LogTrace("Disposing..."); - // yield then acquire the topic semaphore to prevent new calls from starting - await Task.Yield(); - (await topicSendSemaphore.Lock(CancellationToken.None)).Dispose(); // DCT: None available + reattachTopicCts.Cancel(); + var semaphoreLockTask = topicSendSemaphore.Lock(CancellationToken.None); // DCT: None available if (!released) { @@ -363,6 +362,7 @@ public async ValueTask DisposeAsync() if (!released) await Lifetime; // finish the async callback + (await semaphoreLockTask).Dispose(); topicSendSemaphore.Dispose(); } From e6db8713eb38753e1f9098bb0792f472a015d77f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 26 Nov 2023 22:19:26 -0500 Subject: [PATCH 387/717] Increase test timeout for health check tests --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index a5e6f12187f..3f1f52866ac 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -759,7 +759,7 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke ourProcessHandler.Suspend(); - await Task.WhenAny(ourProcessHandler.Lifetime, Task.Delay(TimeSpan.FromMinutes(1), cancellationToken)); + await Task.WhenAny(ourProcessHandler.Lifetime, Task.Delay(TimeSpan.FromMinutes(2), cancellationToken)); Assert.IsTrue(ourProcessHandler.Lifetime.IsCompleted); var timeout = 20; From a979f04e03a2dcc5130cff90ed7a55fdacfc1762 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 27 Nov 2023 12:19:26 -0500 Subject: [PATCH 388/717] Fix race condition in `JobsRequiredTest` cleanup --- .../Live/Instance/JobsRequiredTest.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsRequiredTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsRequiredTest.cs index e7c7cb610c5..c6501e6766a 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsRequiredTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsRequiredTest.cs @@ -50,7 +50,14 @@ public async ValueTask DisposeAsync() { cancellationTokenSource.Cancel(); cancellationTokenSource.Dispose(); - await hubConnectionTask; + try + { + await hubConnectionTask; + } + catch (OperationCanceledException) + { + } + if (hubConnection != null) await hubConnection.DisposeAsync(); } From e4d6c5d4876d2df89b6da192d69c0152c4a597f7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 27 Nov 2023 12:49:55 -0500 Subject: [PATCH 389/717] Fix Process dispose handling Fix read timeout workaround unnecessarily disposing too much --- src/Tgstation.Server.Host/System/Process.cs | 30 ++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/System/Process.cs b/src/Tgstation.Server.Host/System/Process.cs index da67c8f0e89..210a86db8c6 100644 --- a/src/Tgstation.Server.Host/System/Process.cs +++ b/src/Tgstation.Server.Host/System/Process.cs @@ -128,7 +128,7 @@ public Process( /// public async ValueTask DisposeAsync() { - if (Interlocked.Exchange(ref disposed, 1) == 1) + if (Interlocked.Exchange(ref disposed, 1) != 0) return; logger.LogTrace("Disposing PID {pid}...", Id); @@ -146,6 +146,7 @@ public async ValueTask DisposeAsync() /// public async ValueTask GetCombinedOutput(CancellationToken cancellationToken) { + CheckDisposed(); if (readTask == null) throw new InvalidOperationException("Output/Error stream reading was not enabled!"); @@ -158,7 +159,7 @@ public async ValueTask GetCombinedOutput(CancellationToken cancellationT if (!readTask.IsCompleted) { logger.LogWarning("Detected process output read hang on PID {pid}! Closing handle as a workaround...", Id); - await DisposeAsync(); + cancellationTokenSource.Cancel(); } } @@ -168,6 +169,7 @@ public async ValueTask GetCombinedOutput(CancellationToken cancellationT /// public void Terminate() { + CheckDisposed(); if (handle.HasExited) { logger.LogTrace("PID {pid} already exited", Id); @@ -190,6 +192,7 @@ public void Terminate() /// public void AdjustPriority(bool higher) { + CheckDisposed(); var targetPriority = higher ? ProcessPriorityClass.AboveNormal : ProcessPriorityClass.BelowNormal; try { @@ -205,6 +208,7 @@ public void AdjustPriority(bool higher) /// public void Suspend() { + CheckDisposed(); try { processFeatures.SuspendProcess(handle); @@ -220,6 +224,7 @@ public void Suspend() /// public void Resume() { + CheckDisposed(); try { processFeatures.ResumeProcess(handle); @@ -235,6 +240,7 @@ public void Resume() /// public string GetExecutingUsername() { + CheckDisposed(); var result = processFeatures.GetExecutingUsername(handle); logger.LogTrace("PID {pid} Username: {username}", Id, result); return result; @@ -244,6 +250,7 @@ public string GetExecutingUsername() public ValueTask CreateDump(string outputFile, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(outputFile); + CheckDisposed(); logger.LogTrace("Dumping PID {pid} to {dumpFilePath}...", Id, outputFile); return processFeatures.CreateDump(handle, outputFile, cancellationToken); @@ -255,18 +262,29 @@ public ValueTask CreateDump(string outputFile, CancellationToken cancellationTok /// A resulting in the or if the process was detached. async Task WrapLifetimeTask() { + bool hasExited; try { await handle.WaitForExitAsync(cancellationTokenSource.Token); - var exitCode = handle.ExitCode; - logger.LogTrace("PID {pid} exited with code {exitCode}", Id, exitCode); - return exitCode; + hasExited = true; } catch (OperationCanceledException ex) { logger.LogTrace(ex, "Process lifetime task cancelled!"); - return null; + hasExited = handle.HasExited; } + + if (!hasExited) + return null; + + var exitCode = handle.ExitCode; + logger.LogTrace("PID {pid} exited with code {exitCode}", Id, exitCode); + return exitCode; } + + /// + /// Throws an if a method of the was called after . + /// + void CheckDisposed() => ObjectDisposedException.ThrowIf(disposed != 0, this); } } From 2ee1ff4665876f6a36cc35b39288eaa1fe621384 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 27 Nov 2023 14:18:10 -0500 Subject: [PATCH 390/717] Add a yield here to potentially fix a CI error We HAD the handle to the process open and running, yet somehow GetProcessesByName failed to find it. --- .../Live/Instance/WatchdogTest.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 3f1f52866ac..affa17266e6 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -547,7 +547,7 @@ async Task TestDMApiFreeDeploy(CancellationToken cancellationToken) Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value); ValidateSessionId(daemonStatus, true); - CheckDDPriority(); + await CheckDDPriority(); Assert.AreEqual(false, daemonStatus.SoftRestart); Assert.AreEqual(false, daemonStatus.SoftShutdown); Assert.AreEqual(string.Empty, daemonStatus.AdditionalParameters); @@ -618,7 +618,7 @@ async Task RunBasicTest(CancellationToken cancellationToken) Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value); ValidateSessionId(daemonStatus, true); - CheckDDPriority(); + await CheckDDPriority(); Assert.AreEqual(false, daemonStatus.SoftRestart); Assert.AreEqual(false, daemonStatus.SoftShutdown); @@ -715,7 +715,7 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke await WaitForJob(startJob, 40, false, null, cancellationToken); - CheckDDPriority(); + await CheckDDPriority(); // lock on to DD and pause it so it can't health check var ddProcs = TestLiveServer.GetEngineServerProcessesOnPort(testVersion.Engine.Value, ddPort).Where(x => !x.HasExited).ToList(); @@ -1074,8 +1074,9 @@ static void CheckEmbedsTest(MessageContent embedsResponse, DateTimeOffset startT Assert.AreEqual("Footer text", embedsResponse.Embed.Footer?.Text); } - void CheckDDPriority() + async ValueTask CheckDDPriority() { + await Task.Yield(); var allProcesses = TestLiveServer.GetEngineServerProcessesOnPort(testVersion.Engine.Value, ddPort).Where(x => !x.HasExited).ToList(); if (allProcesses.Count == 0) Assert.Fail("Expected engine server to be running here"); @@ -1115,7 +1116,7 @@ async Task RunLongRunningTestThenUpdate(CancellationToken cancellationToken) Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value); ValidateSessionId(daemonStatus, true); - CheckDDPriority(); + await CheckDDPriority(); Assert.AreEqual(initialCompileJob.Id, daemonStatus.ActiveCompileJob.Id); var newerCompileJob = daemonStatus.StagedCompileJob; @@ -1163,7 +1164,7 @@ async Task RunLongRunningTestThenUpdateWithNewDme(CancellationToken cancellation ValidateSessionId(daemonStatus, true); Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value); Assert.AreEqual(true, daemonStatus.SoftRestart); - CheckDDPriority(); + await CheckDDPriority(); Assert.AreEqual(initialCompileJob.Id, daemonStatus.ActiveCompileJob.Id); var newerCompileJob = daemonStatus.StagedCompileJob; @@ -1201,7 +1202,7 @@ async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken await WaitForJob(startJob, 70, false, null, cancellationToken); - CheckDDPriority(); + await CheckDDPriority(); var byondInstallJobTask = instanceClient.Engine.SetActiveVersion( new EngineVersionRequest @@ -1267,7 +1268,7 @@ public async Task StartAndLeaveRunning(CancellationToken cancellationToken) Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status); Assert.IsTrue(daemonStatus.SoftRestart); - CheckDDPriority(); + await CheckDDPriority(); Assert.AreEqual(ddPort, daemonStatus.CurrentPort); // Try killing the DD process to ensure it gets set to the restoring state From 9ba8952809a8a6f3c11ac05ed7c2f00d84010a33 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 28 Nov 2023 08:39:12 -0500 Subject: [PATCH 391/717] Fold Code Scanning into CI Pipeline --- .github/workflows/ci-pipeline.yml | 34 +++++++++++++++++- .github/workflows/code-scanning.yml | 55 ----------------------------- 2 files changed, 33 insertions(+), 56 deletions(-) delete mode 100644 .github/workflows/code-scanning.yml diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 5551c047e3e..f93709905e2 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -82,6 +82,38 @@ jobs: - name: GitHub Requires at Least One Step for a Job run: exit 0 + analyze: + name: Code Scanning + needs: start-ci-run-gate + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + if: (!(cancelled() || failure()) && needs.start-ci-run-gate.result == 'success' && ${{ vars.TGS_ENABLE_CODE_QL }} == 'true') + steps: + - name: Setup dotnet + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} + + - name: Checkout + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: csharp + + - name: Build + run: dotnet build -c ReleaseNoWindows -p:TGS_HOST_NO_WEBPANEL=true + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:csharp" + dmapi-build: name: Build DMAPI needs: start-ci-run-gate @@ -1314,7 +1346,7 @@ jobs: ci-completion-gate: # This job exists so there isn't a moving target for branch protections name: CI Completion Gate - needs: [ pages-build, docker-build, build-deb, build-msi, validate-openapi-spec, upload-code-coverage, check-winget-pr-template ] + needs: [ pages-build, docker-build, build-deb, build-msi, validate-openapi-spec, upload-code-coverage, check-winget-pr-template, analyze ] runs-on: ubuntu-latest if: (!(cancelled() || failure()) && needs.pages-build.result == 'success' && needs.docker-build.result == 'success' && needs.build-deb.result == 'success' && needs.build-msi.result == 'success' && needs.validate-openapi-spec.result == 'success' && needs.upload-code-coverage.result == 'success' && needs.check-winget-pr-template.result == 'success') steps: diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml deleted file mode 100644 index 9442ce55308..00000000000 --- a/.github/workflows/code-scanning.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: 'Code Scanning' - -on: - schedule: - - cron: 0 23 * * 1 - push: - branches: - - dev - - master - - V6 - pull_request: - branches: - - dev - - master - - V6 - -env: - TGS_DOTNET_VERSION: 8 - TGS_DOTNET_QUALITY: ga - -concurrency: - group: "code-scanning-${{ github.head_ref || github.run_id }}-${{ github.event_name }}" - cancel-in-progress: true - -jobs: - analyze: - name: Code Scanning - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - if: ${{ vars.TGS_ENABLE_CODE_QL }} == 'true' - steps: - - name: Setup dotnet - uses: actions/setup-dotnet@v3 - with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' - dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - - - name: Checkout - uses: actions/checkout@v3 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: csharp - - - name: Build - run: dotnet build -c ReleaseNoWindows -p:TGS_HOST_NO_WEBPANEL=true - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: "/language:csharp" From 3b8cbd8e733ecc2a186674376192c5d10033019e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 28 Nov 2023 08:39:55 -0500 Subject: [PATCH 392/717] Change CI cron to 4AM EST --- .github/workflows/ci-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index f93709905e2..2b51152c165 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -19,7 +19,7 @@ name: 'CI Pipeline' on: schedule: - - cron: 0 23 * * * + - cron: 0 9 * * * push: branches: - dev From 6b37808ec5bd70074e7a13de8e8a84eb928faeea Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 28 Nov 2023 09:02:28 -0500 Subject: [PATCH 393/717] Revert "Suppress the NU5104 while we're in preview" This reverts commit 2f9fb5df0c66a20960c3472c2dcb45bdbc2980c6. --- src/Tgstation.Server.Client/Tgstation.Server.Client.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj index 21eff94c4bb..876f1097d6f 100644 --- a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj +++ b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj @@ -7,7 +7,6 @@ Client library for tgstation-server. json web api tgstation-server tgstation ss13 byond client http $(TGS_NUGET_RELEASE_NOTES_CLIENT) - NU5104 From 0b5a36fea2bfc5e74f2935da962dddf23502cc19 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 29 Nov 2023 15:06:57 -0500 Subject: [PATCH 394/717] Do not start database services we're not using See https://github.com/actions/runner/issues/822#issuecomment-1524826092 --- .github/workflows/ci-pipeline.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 2b51152c165..796cf6797af 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -625,14 +625,14 @@ jobs: if: (!(cancelled() || failure()) && needs.dmapi-build.result == 'success' && needs.opendream-build.result == 'success') services: # We start all dbs here so we can just code the stuff once mssql: - image: mcr.microsoft.com/mssql/server:2019-latest + image: ${{ (matrix.database-type == 'SqlServer') && 'mcr.microsoft.com/mssql/server:2019-latest' || '' }} env: SA_PASSWORD: myPassword ACCEPT_EULA: 'Y' ports: - 1433:1433 postgres: - image: cyberboss/postgres-max-connections # Fork of _/postgres:latest with max_connections=500 becuase GitHub actions service containers have no way to set command lines. Rebuilds with updates. + image: ${{ (matrix.database-type == 'PostgresSql') && 'cyberboss/postgres-max-connections' || '' }} # Fork of _/postgres:latest with max_connections=500 becuase GitHub actions service containers have no way to set command lines. Rebuilds with updates. ports: - 5432:5432 env: @@ -643,7 +643,7 @@ jobs: --health-timeout 5s --health-retries 5 mariadb: - image: mariadb + image: ${{ (matrix.database-type == 'MariaDB') && 'mariadb' || '' }} ports: - 3306:3306 env: @@ -654,7 +654,7 @@ jobs: --health-timeout=2s --health-retries=3 mysql: - image: mysql:5.7.31 + image: ${{ (matrix.database-type == 'MySql') && 'mysql:5.7.31' || '' }} ports: - 3307:3306 env: From 1016596e5d18e6397b28e9c6221fc3d489340b7c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 29 Nov 2023 15:11:11 -0500 Subject: [PATCH 395/717] Add a missing comment to CI --- .github/workflows/ci-pipeline.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 796cf6797af..79bc7767198 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -2,6 +2,7 @@ # Does CI on push/PR/cron. Deployments on push when triggered # - Validates Documentation # - Builds C# and DMAPI +# - Runs CodeQL Anaylsis # - Tests everything on massive matrix # - Packages # - Tests package installs/services/uninstalls From b5f7a7f06959a5446afcb5c1e7b0a0b64958f1c3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 29 Nov 2023 16:43:30 -0500 Subject: [PATCH 396/717] Fix main page logo not appearing if webpanel was disabled --- .../Controllers/ControlPanelController.cs | 23 +++------ .../Controllers/RootController.cs | 49 ++++++++++++++++--- .../Extensions/ControllerBaseExtensions.cs | 39 +++++++++++++++ .../Views/Root/Index.cshtml | 3 +- tests/Tgstation.Server.Tests/TestVersions.cs | 8 +-- 5 files changed, 93 insertions(+), 29 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs b/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs index 08d8f74dad1..d69947d4ba9 100644 --- a/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs +++ b/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs @@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; @@ -15,6 +14,7 @@ using Tgstation.Server.Api; using Tgstation.Server.Host.Configuration; +using Tgstation.Server.Host.Extensions; namespace Tgstation.Server.Host.Controllers { @@ -136,22 +136,11 @@ public IActionResult Get([FromRoute] string appRoute) if (Request.Headers.ContainsKey(FetchChannelVaryHeader)) return GetChannelJson(); - var fileInfo = hostEnvironment.WebRootFileProvider.GetFileInfo(appRoute); - if (fileInfo.Exists) - { - logger.LogTrace("Serving static file \"{filename}\"...", appRoute); - var contentTypeProvider = new FileExtensionContentTypeProvider(); - if (!contentTypeProvider.TryGetContentType(fileInfo.Name, out var contentType)) - contentType = MediaTypeNames.Application.Octet; - else if (contentType == MediaTypeNames.Application.Json) - Response.Headers.Add( - HeaderNames.CacheControl, - new StringValues(new[] { "public", "max-age=31536000", "immutable" })); - - return File(appRoute, contentType); - } - else - logger.LogTrace("Requested static file \"{filename}\" does not exist! Redirecting to index...", appRoute); + var foundFile = this.TryServeFile(hostEnvironment, logger, appRoute); + if (foundFile != null) + return foundFile; + + logger.LogTrace("Requested static file \"{filename}\" does not exist! Redirecting to index...", appRoute); return File("index.html", MediaTypeNames.Text.Html); } diff --git a/src/Tgstation.Server.Host/Controllers/RootController.cs b/src/Tgstation.Server.Host/Controllers/RootController.cs index 850785d6125..5de25b1451a 100644 --- a/src/Tgstation.Server.Host/Controllers/RootController.cs +++ b/src/Tgstation.Server.Host/Controllers/RootController.cs @@ -2,10 +2,13 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Tgstation.Server.Host.Configuration; +using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; @@ -19,14 +22,14 @@ namespace Tgstation.Server.Host.Controllers public sealed class RootController : Controller { /// - /// The route to the TGS logo .svg in the on Windows. + /// The name of the TGS logo .svg in the on Windows. /// - public const string ProjectLogoSvgRouteWindows = "/0176d5d8b7d307f158e0.svg"; + const string LogoSvgWindowsName = "0176d5d8b7d307f158e0"; /// - /// The route to the TGS logo .svg in the on Linux. + /// The name of the TGS logo .svg in the on Linux. /// - public const string ProjectLogoSvgRouteLinux = "/b5616c99bf2052a6bbd7.svg"; + const string LogoSvgLinuxName = "b5616c99bf2052a6bbd7"; /// /// The for the . @@ -38,6 +41,16 @@ public sealed class RootController : Controller /// readonly IPlatformIdentifier platformIdentifier; + /// + /// THe for the . + /// + readonly IWebHostEnvironment hostEnvironment; + + /// + /// The for the . + /// + readonly ILogger logger; + /// /// The for the . /// @@ -53,16 +66,22 @@ public sealed class RootController : Controller /// /// The value of . /// The value of . + /// The value of . + /// The value of . /// The containing the value of . /// The containing the value of . public RootController( IAssemblyInformationProvider assemblyInformationProvider, IPlatformIdentifier platformIdentifier, + IWebHostEnvironment hostEnvironment, + ILogger logger, IOptions generalConfigurationOptions, IOptions controlPanelConfigurationOptions) { this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); + this.hostEnvironment = hostEnvironment ?? throw new ArgumentNullException(nameof(hostEnvironment)); + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); controlPanelConfiguration = controlPanelConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(controlPanelConfigurationOptions)); } @@ -98,13 +117,29 @@ public IActionResult Index() var model = new { Links = links, - Svg = platformIdentifier.IsWindows // these are different because of motherfucking line endings -_- - ? ProjectLogoSvgRouteWindows - : ProjectLogoSvgRouteLinux, Title = assemblyInformationProvider.VersionString, }; return View(model); } + + /// + /// Retrieve the logo .svg for the webpanel. + /// + /// The appropriate . + [HttpGet("logo.svg")] + public IActionResult GetLogo() + { +#if NO_WEBPANEL + logger.LogTrace("Cannot serve project logo as TGS was built without the webpanel!"); + return NotFound(); +#else + var logoFileName = platformIdentifier.IsWindows // these are different because of motherfucking line endings -_- + ? LogoSvgWindowsName + : LogoSvgLinuxName; + + return (IActionResult)this.TryServeFile(hostEnvironment, logger, $"{logoFileName}.svg"); +#endif + } } } diff --git a/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs b/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs index 9ab3b1cc87e..2d1d8119a0f 100644 --- a/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/ControllerBaseExtensions.cs @@ -1,7 +1,13 @@ using System; using System.Net; +using System.Net.Mime; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; @@ -30,5 +36,38 @@ public static ObjectResult Gone(this ControllerBase controller) /// A with the given . public static ObjectResult StatusCode(this ControllerBase controller, HttpStatusCode statusCode, object errorMessage) => controller?.StatusCode((int)statusCode, errorMessage) ?? throw new ArgumentNullException(nameof(controller)); + + /// + /// Try to serve a given file . + /// + /// The . + /// The . + /// The . + /// The path to the file in the 'wwwroot'. + /// A if the file was found. otherwise. + public static VirtualFileResult TryServeFile(this ControllerBase controller, IWebHostEnvironment hostEnvironment, ILogger logger, string path) + { + ArgumentNullException.ThrowIfNull(controller); + ArgumentNullException.ThrowIfNull(hostEnvironment); + ArgumentNullException.ThrowIfNull(logger); + ArgumentNullException.ThrowIfNull(path); + + var fileInfo = hostEnvironment.WebRootFileProvider.GetFileInfo(path); + if (fileInfo.Exists) + { + logger.LogTrace("Serving static file \"{filename}\"...", path); + var contentTypeProvider = new FileExtensionContentTypeProvider(); + if (!contentTypeProvider.TryGetContentType(fileInfo.Name, out var contentType)) + contentType = MediaTypeNames.Application.Octet; + else if (contentType == MediaTypeNames.Application.Json) + controller.Response.Headers.Add( + HeaderNames.CacheControl, + new StringValues(new[] { "public", "max-age=31536000", "immutable" })); + + return controller.File(path, contentType); + } + + return null; + } } } diff --git a/src/Tgstation.Server.Host/Views/Root/Index.cshtml b/src/Tgstation.Server.Host/Views/Root/Index.cshtml index 209a6ad5ac9..bc23093e87c 100644 --- a/src/Tgstation.Server.Host/Views/Root/Index.cshtml +++ b/src/Tgstation.Server.Host/Views/Root/Index.cshtml @@ -1,5 +1,4 @@ @{ - var svgPath = Model.Svg; var title = Model.Title; @@ -13,7 +12,7 @@ - + @{ if (Model.Links != null) foreach (KeyValuePair kvp in Model.Links) diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 03b998d438d..3dd20d8e7b0 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -416,11 +416,13 @@ public async Task CheckWebRootPathForTgsLogo() if (!Directory.Exists(directory)) Assert.Inconclusive("Webpanel not built?"); + static string GetConstField(string name) => (string)typeof(RootController).GetField(name, BindingFlags.NonPublic | BindingFlags.Static).GetValue(null); + var logo = new PlatformIdentifier().IsWindows - ? RootController.ProjectLogoSvgRouteWindows - : RootController.ProjectLogoSvgRouteLinux; + ? GetConstField("LogoSvgWindowsName") + : GetConstField("LogoSvgLinuxName"); - var path = $"../../../../../src/Tgstation.Server.Host/wwwroot{logo}"; + var path = $"../../../../../src/Tgstation.Server.Host/wwwroot/{logo}.svg"; Assert.IsTrue(File.Exists(path)); var content = await File.ReadAllBytesAsync(path); From 2702a2fc2b3568fb149fcad2668287689747d829 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 29 Nov 2023 17:15:39 -0500 Subject: [PATCH 397/717] Log path repositories are cloned to --- .../Components/Repository/RepositoryManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs index 2940e0d1349..5852a58f972 100644 --- a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs +++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs @@ -127,8 +127,6 @@ public async ValueTask CloneRepository( CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(url); - - logger.LogInformation("Begin clone {url} (Branch: {initialBranch})", url, initialBranch); lock (semaphore) { if (CloneInProgress) @@ -136,12 +134,14 @@ public async ValueTask CloneRepository( CloneInProgress = true; } + var repositoryPath = ioManager.ResolvePath(); + logger.LogInformation("Begin clone {url} to {path} (Branch: {initialBranch})", url, repositoryPath, initialBranch); + try { using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken)) { logger.LogTrace("Semaphore acquired for clone"); - var repositoryPath = ioManager.ResolvePath(); if (!await ioManager.DirectoryExists(repositoryPath, cancellationToken)) try { From c40197fcb58b24e9914bec5231b81b7cb2a19eed Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 29 Nov 2023 17:32:26 -0500 Subject: [PATCH 398/717] Specify `Environment.SpecialFolderOption` where possible Also fix a typo --- src/Tgstation.Server.Host.Service/Program.cs | 4 +++- .../Components/Engine/ByondInstallerBase.cs | 8 +------- .../Components/Engine/PosixByondInstaller.cs | 3 ++- .../Components/Engine/WindowsByondInstaller.cs | 11 ++++++----- .../Configuration/FileLoggingConfiguration.cs | 4 +++- src/Tgstation.Server.Host/Core/Application.cs | 4 +++- tests/Tgstation.Server.Tests/CachingFileDownloader.cs | 4 +++- .../Live/Instance/InstanceTest.cs | 4 +++- 8 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/Tgstation.Server.Host.Service/Program.cs b/src/Tgstation.Server.Host.Service/Program.cs index c2f72b09010..4a9d39fcd21 100644 --- a/src/Tgstation.Server.Host.Service/Program.cs +++ b/src/Tgstation.Server.Host.Service/Program.cs @@ -179,7 +179,9 @@ void InvokeSC(string? serviceToUninstall) var exePath = Path.Combine(assemblyDirectory, $"{assemblyNameWithoutExtension}.exe"); var programDataDirectory = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), + Environment.GetFolderPath( + Environment.SpecialFolder.CommonApplicationData, + Environment.SpecialFolderOption.DoNotVerify), Server.Common.Constants.CanonicalPackageName); using var processInstaller = new ServiceProcessInstaller(); diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index cf20d498a97..f02239969f7 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -52,7 +52,7 @@ abstract class ByondInstallerBase : EngineInstallerBase protected override EngineType TargetEngineType => EngineType.Byond; /// - /// Bath to the system user's local BYOND folder. + /// Path to the system user's local BYOND folder. /// protected abstract string PathToUserFolder { get; } @@ -157,12 +157,6 @@ public override async ValueTask TrustDmbPath(EngineVersion version, string fullD ArgumentNullException.ThrowIfNull(fullDmbPath); var byondDir = PathToUserFolder; - if (String.IsNullOrWhiteSpace(byondDir)) - { - Logger.LogTrace("No relevant user BYOND directory to install a \"{fileName}\" in", TrustedDmbFileName); - return; - } - var cfgDir = IOManager.ConcatPath( byondDir, CfgDirectoryName); diff --git a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs index cddace53c8c..f3c9c561b18 100644 --- a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs @@ -65,7 +65,8 @@ public PosixByondInstaller( PathToUserFolder = IOManager.ResolvePath( IOManager.ConcatPath( Environment.GetFolderPath( - Environment.SpecialFolder.UserProfile), + Environment.SpecialFolder.UserProfile, + Environment.SpecialFolderOption.DoNotVerify), "./byond/cache")); } diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 0ebf63ff9fe..0f40d3f5388 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -100,11 +100,12 @@ public WindowsByondInstaller( this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); - var documentsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); - if (String.IsNullOrWhiteSpace(documentsDirectory)) - PathToUserFolder = null; // happens with the service account - else - PathToUserFolder = IOManager.ResolvePath(IOManager.ConcatPath(documentsDirectory, "BYOND")); + var documentsDirectory = Environment.GetFolderPath( + Environment.SpecialFolder.MyDocuments, + Environment.SpecialFolderOption.DoNotVerify); + + PathToUserFolder = IOManager.ResolvePath( + IOManager.ConcatPath(documentsDirectory, "BYOND")); semaphore = new SemaphoreSlim(1); installedDirectX = false; diff --git a/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs b/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs index aa798cfed36..c317fc1b97d 100644 --- a/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs @@ -62,7 +62,9 @@ public string GetFullLogDirectory( return platformIdentifier.IsWindows ? ioManager.ConcatPath( - Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), + Environment.GetFolderPath( + Environment.SpecialFolder.CommonApplicationData, + Environment.SpecialFolderOption.DoNotVerify), assemblyInformationProvider.VersionPrefix, "logs") : ioManager.ConcatPath( diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 3ce52f39beb..10f27284658 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -367,7 +367,9 @@ void AddTypedContext() // only global repo manager should be for the OD repo var openDreamRepositoryDirectory = ioManager.ConcatPath( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + Environment.GetFolderPath( + Environment.SpecialFolder.LocalApplicationData, + Environment.SpecialFolderOption.DoNotVerify), assemblyInformationProvider.VersionPrefix, "OpenDreamRepository"); services.AddSingleton( diff --git a/tests/Tgstation.Server.Tests/CachingFileDownloader.cs b/tests/Tgstation.Server.Tests/CachingFileDownloader.cs index bd7d01bbbdb..de540b606d6 100644 --- a/tests/Tgstation.Server.Tests/CachingFileDownloader.cs +++ b/tests/Tgstation.Server.Tests/CachingFileDownloader.cs @@ -94,7 +94,9 @@ public static async ValueTask InitializeByondVersion(ILogger logger, Version byo // actions is supposed to cache BYOND for us var dir = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile, + Environment.SpecialFolderOption.DoNotVerify), "byond-zips-cache", windows ? "windows" : "linux"); path = Path.Combine( diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index fc5177e3558..611ee9ed6fc 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -85,7 +85,9 @@ public static async ValueTask DownloadEngineVersion( { var ioManager = new DefaultIOManager(); var odRepoDir = ioManager.ConcatPath( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + Environment.GetFolderPath( + Environment.SpecialFolder.LocalApplicationData, + Environment.SpecialFolderOption.DoNotVerify), new AssemblyInformationProvider().VersionPrefix, "OpenDreamRepository"); var odRepoIoManager = new ResolvingIOManager(ioManager, odRepoDir); From 864572b252401fcecfa60bcba46b6196a09ddfc4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 29 Nov 2023 18:04:16 -0500 Subject: [PATCH 399/717] Documentation update for OD/Linux --- README.md | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 8ca58e05605..191499f053e 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This is a toolset to manage production BYOND servers. It includes the ability to ### Pre-Requisites -_Note: If you opt to use the Windows installer, all pre-requisites (including MariaDB) are provided out of the box._ +_Note: If you opt to use the Windows installer, all pre-requisites for running BYOND servers (including MariaDB) are provided out of the box. If you wish to use OpenDream you will need to install the required dotnet SDK manually._ tgstation-server needs a relational database to store it's data. @@ -101,9 +101,19 @@ If using the console version, run `./tgs.bat` in the root of the installation di Installing natively is the recommended way to run tgstation-server on Linux. -##### Ubuntu +##### Ubuntu/Debian Package -Install TGS and all it's dependencies via our apt repository, interactively configure it, and start the service with this one-liner: +You first need to add the appropriate Microsoft package repository for your distribution + +Refer to the Microsoft website for steps for + +- [Ubuntu](https://learn.microsoft.com/en-us/dotnet/core/install/linux-ubuntu#register-the-microsoft-package-repository) +- [Debian 12](https://learn.microsoft.com/en-us/dotnet/core/install/linux-debian#debian-12) +- [Debian 11](https://learn.microsoft.com/en-us/dotnet/core/install/linux-debian#debian-11) +- [Debian 10](https://learn.microsoft.com/en-us/dotnet/core/install/linux-debian#debian-10) +- [Other Distros](https://learn.microsoft.com/en-us/dotnet/core/install/linux-scripted-manual#manual-install) + +After that, install TGS and all it's dependencies via our apt repository, interactively configure it, and start the service with this one-liner: ```sh sudo dpkg --add-architecture i386 \ @@ -119,25 +129,11 @@ sudo dpkg --add-architecture i386 \ The service will execute as the newly created user: `tgstation-server`. -##### Debian - -The `aspnetcore-runtime-8.0` package isn't yet available on mainline Debian and must be [installed from Microsoft](https://learn.microsoft.com/en-us/dotnet/core/install/linux-debian) first. Use the following one-liner to add their packages repository. - -```sh -curl -L https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -o packages-microsoft-prod.deb \ -&& sudo dpkg -i packages-microsoft-prod.deb \ -&& rm packages-microsoft-prod.deb -``` - -After that, run the same command as the Ubuntu installation. - -_Support for more distros coming soon_ - -##### Manual +##### Manual Setup The following dependencies are required. -- aspnetcore-runtime-8.0 (Note, not all supported distros have this package, see the links above for official Microsoft installation instructions) +- aspnetcore-runtime-8.0 (See Prerequisites under the `Ubuntu/Debian Package` section) - libc6-i386 - libstdc++6:i386 - gcc-multilib (Only on 64-bit systems) @@ -185,6 +181,21 @@ Note that automatic configuration reloading is currently not supported in the co If using manual configuration, before starting your container make sure the aforementioned `appsettings.Production.yml` is setup properly. See below +#### OpenDream + +In order for TGS to use [OpenDream](https://github.com/OpenDreamProject/OpenDream), it requires the full .NET SDK to build whichever version your servers target. Whatever that is, it must be available using the `dotnet` command for whichever user runs TGS. + +OpenDream currently requires [.NET SDK 7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) at the time of this writing. You must install this manually. + +On Linux, as long as OpenDream and TGS do not use the same .NET major version, you cannot achieve this with the package manager as they will conflict. The 7.0 SDK can be added to an 8.0 runtime installation via the following steps. + +1. Install `tgstation-server` using any of the above methods. +1. [Download the Linux SDK binaries](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) for your selected architecture. +1. Extract ONLY the contents of the `sdk` directory in the `.tar.gz` to `/usr/share/dotnet/sdk/` +1. Run `sudo chown -R root /usr/share/dotnet/sdk` + +You should now be able to run the `dotnet --list-sdks` command and see an entry for `7.0.XXX [/usr/share/dotnet/sdk]`. + ### Configuring The first time you run TGS you should be prompted with a configuration wizard which will guide you through setting up your `appsettings.Production.yml` From 647d13f041d9b15eb34a51b04c84ce538fd2160a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 29 Nov 2023 18:25:51 -0500 Subject: [PATCH 400/717] Fix `NO_WEBPANEL` builds --- src/Tgstation.Server.Host/Controllers/RootController.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/RootController.cs b/src/Tgstation.Server.Host/Controllers/RootController.cs index 5de25b1451a..3ccca028fea 100644 --- a/src/Tgstation.Server.Host/Controllers/RootController.cs +++ b/src/Tgstation.Server.Host/Controllers/RootController.cs @@ -130,16 +130,11 @@ public IActionResult Index() [HttpGet("logo.svg")] public IActionResult GetLogo() { -#if NO_WEBPANEL - logger.LogTrace("Cannot serve project logo as TGS was built without the webpanel!"); - return NotFound(); -#else var logoFileName = platformIdentifier.IsWindows // these are different because of motherfucking line endings -_- ? LogoSvgWindowsName : LogoSvgLinuxName; - return (IActionResult)this.TryServeFile(hostEnvironment, logger, $"{logoFileName}.svg"); -#endif + return (IActionResult)this.TryServeFile(hostEnvironment, logger, $"{logoFileName}.svg") ?? NotFound(); } } } From 5b42ad0f8f6d8f7ed8e51efc4c4dfc7fb8966fd4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 2 Dec 2023 11:36:12 -0500 Subject: [PATCH 401/717] Weeding out JobsHubTest errors --- .../Live/Instance/JobsHubTests.cs | 39 ++++++++++++++----- .../Live/TestLiveServer.cs | 2 +- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index d9456c22bcd..e5f6bd0225c 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -84,7 +84,7 @@ public Task ReceiveJobUpdate(JobResponse job, CancellationToken cancellationToke } } - public async Task Run(CancellationToken cancellationToken) + public async Task Run(CancellationToken cancellationToken) { var neverReceiver = new ShouldNeverReceiveUpdates() { @@ -98,16 +98,32 @@ public async Task Run(CancellationToken cancellationToken) }, }; - await using (permedConn = (HubConnection)await permedUser.SubscribeToJobUpdates( + permedConn = (HubConnection)await permedUser.SubscribeToJobUpdates( this, null, null, - cancellationToken)) - await using (permlessConn = (HubConnection)await permlessUser.SubscribeToJobUpdates( - neverReceiver, - null, - null, - cancellationToken)) + cancellationToken); + + try + { + permlessConn = (HubConnection)await permlessUser.SubscribeToJobUpdates( + neverReceiver, + null, + null, + cancellationToken); + } + catch + { + await permedConn.DisposeAsync(); + } + + return FinishAsync(cancellationToken); + } + + async Task FinishAsync(CancellationToken cancellationToken) + { + await using (permedConn) + await using (permlessConn) { Console.WriteLine($"Initial conn1: {permedConn.ConnectionId}"); Console.WriteLine($"Initial conn2: {permlessConn.ConnectionId}"); @@ -193,10 +209,15 @@ static DateTimeOffset PerformDBTruncation(DateTimeOffset original) } } + static string JobListFormatter(IEnumerable jobs) => String.Join(Environment.NewLine, jobs.Select(x => $"- I:{x.InstanceId}|JID:{x.Id}|JC:{x.JobCode}|Desc:{x.Description}")); + // some instances may be detached, but our cache remains var accountedJobs = allJobs.Count - missableMissedJobs; var accountedSeenJobs = seenJobs.Where(x => allInstances.Any(i => i.Id.Value == x.Value.InstanceId)).ToList(); - Assert.AreEqual(accountedJobs, accountedSeenJobs.Count, $"Mismatch in seen jobs:{Environment.NewLine}{String.Join(Environment.NewLine, allJobs.Where(x => !seenJobs.Any(y => y.Key == x.Id.Value)).Select(x => $"- I:{x.InstanceId}|JID:{x.Id}|JC:{x.JobCode}|Desc:{x.Description}"))}"); + Assert.AreEqual( + accountedJobs, + accountedSeenJobs.Count, + $"Mismatch in seen jobs:{Environment.NewLine}Not seen in seen:{Environment.NewLine}{JobListFormatter(allJobs.Where(x => !seenJobs.Any(y => y.Key == x.Id.Value)))}{Environment.NewLine}Seen not in all:{Environment.NewLine}{JobListFormatter(seenJobs.Values.Where(x => !allJobs.Any(y => y.Id.Value == x.Id.Value)))}"); Assert.IsTrue(accountedJobs <= seenJobs.Count); Assert.AreNotEqual(0, permlessSeenJobs.Count); Assert.IsTrue(permlessSeenJobs.Count < seenJobs.Count); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index a419fc648c1..8aea9eb1eac 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1395,11 +1395,11 @@ async Task FailFast(Task task) InstanceResponse odInstance, compatInstance; if (!openDreamOnly) { + jobsHubTestTask = FailFast(await jobsHubTest.Run(cancellationToken)); // returns Task var rootTest = FailFast(RawRequestTests.Run(clientFactory, firstAdminClient, cancellationToken)); var adminTest = FailFast(new AdministrationTest(firstAdminClient.Administration).Run(cancellationToken)); var usersTest = FailFast(new UsersTest(firstAdminClient).Run(cancellationToken)); - jobsHubTestTask = FailFast(jobsHubTest.Run(cancellationToken)); var instanceManagerTest = new InstanceManagerTest(firstAdminClient, server.Directory); var compatInstanceTask = instanceManagerTest.CreateTestInstance("CompatTestsInstance", cancellationToken); var odInstanceTask = instanceManagerTest.CreateTestInstance("OdTestsInstance", cancellationToken); From c1edbed40c5064cb7dd971437cca34a589d2e5cc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 2 Dec 2023 17:13:20 -0500 Subject: [PATCH 402/717] Fix Linux .NET 7 SDK side-by-side install guide --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 191499f053e..d2830e93d9a 100644 --- a/README.md +++ b/README.md @@ -191,8 +191,8 @@ On Linux, as long as OpenDream and TGS do not use the same .NET major version, y 1. Install `tgstation-server` using any of the above methods. 1. [Download the Linux SDK binaries](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) for your selected architecture. -1. Extract ONLY the contents of the `sdk` directory in the `.tar.gz` to `/usr/share/dotnet/sdk/` -1. Run `sudo chown -R root /usr/share/dotnet/sdk` +1. Extract everything EXCEPT the `dotnet` executable, `LICENSE.txt``, and `ThirdPartyNotices.txt` in the `.tar.gz` on top of the existing installation directory `/usr/share/dotnet/` +1. Run `sudo chown -R root /usr/share/dotnet` You should now be able to run the `dotnet --list-sdks` command and see an entry for `7.0.XXX [/usr/share/dotnet/sdk]`. From f406a897a20e79bb3e6f9b3674a29b46075952e9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 3 Dec 2023 13:49:48 -0500 Subject: [PATCH 403/717] Fix a typo in `Chunker` --- .../Components/Interop/Chunker.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Chunker.cs b/src/Tgstation.Server.Host/Components/Interop/Chunker.cs index d6a0c7c024e..85f6de0d6c4 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Chunker.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Chunker.cs @@ -57,15 +57,15 @@ protected Chunker(ILogger logger) /// /// Process a given . /// - /// The of communication that was chunked. + /// The of communication that was chunked. /// The of expected. - /// The callback that receives the completed . + /// The callback that receives the completed . /// The callback that generates a for a given error. /// The . /// The for the operation. /// A resulting in the for the chunked request. - protected async ValueTask ProcessChunk( - Func> completionCallback, + protected async ValueTask ProcessChunk( + Func> completionCallback, Func chunkErrorCallback, ChunkData chunk, CancellationToken cancellationToken) @@ -128,11 +128,11 @@ protected async ValueTask ProcessChunk( chunkSets.Remove(requestInfo.PayloadId.Value); } - TCommnication completedCommunication; + TCommunication completedCommunication; var fullCommunicationJson = String.Concat(payloads); try { - completedCommunication = JsonConvert.DeserializeObject(fullCommunicationJson, DMApiConstants.SerializerSettings); + completedCommunication = JsonConvert.DeserializeObject(fullCommunicationJson, DMApiConstants.SerializerSettings); } catch (Exception ex) { From b29d93a66a6b7f21800def23cbf90132400569e6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 3 Dec 2023 13:59:28 -0500 Subject: [PATCH 404/717] Migrate priority topic sending to an extension --- .../Components/Session/SessionController.cs | 38 +++-------- .../Extensions/TopicClientExtensions.cs | 68 +++++++++++++++++++ 2 files changed, 77 insertions(+), 29 deletions(-) create mode 100644 src/Tgstation.Server.Host/Extensions/TopicClientExtensions.cs diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 9094cdf5273..cefdcff76db 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -22,6 +21,7 @@ using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.Components.Interop.Topic; +using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; @@ -884,35 +884,15 @@ async ValueTask SendRawTopic(string queryString, bool pri } var targetPort = ReattachInformation.Port; - Byond.TopicSender.TopicResponse byondResponse = null; - var firstSend = true; - + Byond.TopicSender.TopicResponse byondResponse; using (await topicSendSemaphore.Lock(cancellationToken)) - { - const int PrioritySendAttempts = 5; - var endpoint = new IPEndPoint(IPAddress.Loopback, targetPort); - for (var i = PrioritySendAttempts - 1; i >= 0 && (priority || firstSend); --i) - try - { - firstSend = false; - - Logger.LogTrace("Begin topic request"); - byondResponse = await byondTopicSender.SendTopic( - endpoint, - queryString, - cancellationToken); - - Logger.LogTrace("End topic request"); - break; - } - catch (Exception ex) when (ex is not OperationCanceledException) - { - Logger.LogWarning(ex, "SendTopic exception!{retryDetails}", priority ? $" {i} attempts remaining." : String.Empty); - - if (priority && i > 0) - await asyncDelayer.Delay(TimeSpan.FromSeconds(2), cancellationToken); - } - } + byondResponse = await byondTopicSender.SendWithOptionalPriority( + asyncDelayer, + Logger, + queryString, + targetPort, + priority, + cancellationToken); if (byondResponse == null) { diff --git a/src/Tgstation.Server.Host/Extensions/TopicClientExtensions.cs b/src/Tgstation.Server.Host/Extensions/TopicClientExtensions.cs new file mode 100644 index 00000000000..07cd38bd1f6 --- /dev/null +++ b/src/Tgstation.Server.Host/Extensions/TopicClientExtensions.cs @@ -0,0 +1,68 @@ +using System; +using System.Net; +using System.Threading; +using System.Threading.Tasks; + +using Byond.TopicSender; + +using Microsoft.Extensions.Logging; + +using Tgstation.Server.Host.Utils; + +namespace Tgstation.Server.Host.Extensions +{ + /// + /// Extension methods for . + /// + static class TopicClientExtensions + { + /// + /// Send a with optional repeated priority. + /// + /// The to send with. + /// The to use for delayed retries if an error occurs. + /// The to write to. + /// The to send. + /// The local port to send the topic to. + /// If priority retries should be used. + /// The for the operation. + /// A resulting in the on success, on failure. + public static async ValueTask SendWithOptionalPriority( + this ITopicClient topicClient, + IAsyncDelayer delayer, + ILogger logger, + string queryString, + ushort port, + bool priority, + CancellationToken cancellationToken) + { + const int PrioritySendAttempts = 5; + var endpoint = new IPEndPoint(IPAddress.Loopback, port); + var firstSend = true; + + for (var i = PrioritySendAttempts - 1; i >= 0 && (priority || firstSend); --i) + try + { + firstSend = false; + + logger.LogTrace("Begin topic request"); + var byondResponse = await topicClient.SendTopic( + endpoint, + queryString, + cancellationToken); + + logger.LogTrace("End topic request"); + return byondResponse; + } + catch (Exception ex) when (ex is not OperationCanceledException) + { + logger.LogWarning(ex, "SendTopic exception!{retryDetails}", priority ? $" {i} attempts remaining." : String.Empty); + + if (priority && i > 0) + await delayer.Delay(TimeSpan.FromSeconds(2), cancellationToken); + } + + return null; + } + } +} From 060bd6126db8bd64e2d9086d7bc232c747619826 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 3 Dec 2023 14:09:29 -0500 Subject: [PATCH 405/717] Switch to using topic extension method in tests --- .../Live/Instance/WatchdogTest.cs | 72 +++++++++++-------- .../Live/TestLiveServer.cs | 12 ++-- 2 files changed, 50 insertions(+), 34 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index affa17266e6..e011fcc1783 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -208,7 +208,9 @@ async ValueTask RunTest(bool useTrusted) // reimplement TellWorldToReboot because it expects a new deployment and we don't care System.Console.WriteLine("TEST: Hack world reboot topic..."); - var result = await topicClient.SendTopic(IPAddress.Loopback, "tgs_integration_test_special_tactics=1", FindTopicPort(), cancellationToken); + var result = await SendTestTopic( + "tgs_integration_test_special_tactics=1", + cancellationToken); Assert.AreEqual("ack", result.StringData); using var tempCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); @@ -234,13 +236,25 @@ async ValueTask RunTest(bool useTrusted) await RunTest(false); } - async ValueTask BroadcastTest(CancellationToken cancellationToken) + async ValueTask SendTestTopic(string queryString, CancellationToken cancellationToken) { - var topicRequestResult = await topicClient.SendTopic( - IPAddress.Loopback, - $"tgs_integration_test_tactics_broadcast=1", + using var loggerFactory = LoggerFactory.Create(builder => + { + builder.AddConsole(); + builder.SetMinimumLevel(LogLevel.Trace); + }); + return await topicClient.SendWithOptionalPriority( + new AsyncDelayer(), + loggerFactory.CreateLogger(), + queryString, FindTopicPort(), + true, cancellationToken); + } + + async ValueTask BroadcastTest(CancellationToken cancellationToken) + { + var topicRequestResult = await SendTestTopic("tgs_integration_test_tactics_broadcast=1", cancellationToken); Assert.IsNotNull(topicRequestResult); Assert.AreEqual("!!NULL!!", topicRequestResult.StringData); @@ -251,10 +265,8 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest BroadcastMessage = TestBroadcastMessage, }, cancellationToken); - topicRequestResult = await topicClient.SendTopic( - IPAddress.Loopback, - $"tgs_integration_test_tactics_broadcast=1", - FindTopicPort(), + topicRequestResult = await SendTestTopic( + "tgs_integration_test_tactics_broadcast=1", cancellationToken); Assert.IsNotNull(topicRequestResult); @@ -324,10 +336,8 @@ async ValueTask RegressionTest1550(CancellationToken cancellationToken) ValidateSessionId(currentStatus, true); Assert.AreEqual(expectedStaged.Id, currentStatus.ActiveCompileJob.Id); - var topicRequestResult = await topicClient.SendTopic( - IPAddress.Loopback, - $"shadow_wizard_money_gang=1", - FindTopicPort(), + var topicRequestResult = await SendTestTopic( + "shadow_wizard_money_gang=1", cancellationToken); Assert.IsNotNull(topicRequestResult); @@ -456,10 +466,8 @@ async Task TestDeleteByondInstallErrorCasesAndQueing(CancellationTo async Task SendChatOverloadCommand(CancellationToken cancellationToken) { // for the code coverage really... - var topicRequestResult = await topicClient.SendTopic( - IPAddress.Loopback, - $"tgs_integration_test_tactics5=1", - FindTopicPort(), + var topicRequestResult = await SendTestTopic( + "tgs_integration_test_tactics5=1", cancellationToken); Assert.IsNotNull(topicRequestResult); @@ -740,10 +748,8 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke Assert.IsFalse(ddProc.HasExited); // check DD agrees - var topicRequestResult = await topicClient.SendTopic( - IPAddress.Loopback, - $"tgs_integration_test_tactics8=1", - FindTopicPort(), + var topicRequestResult = await SendTestTopic( + "tgs_integration_test_tactics8=1", cancellationToken); Assert.IsNotNull(topicRequestResult); @@ -852,7 +858,9 @@ async Task WhiteBoxValidateBridgeRequestLimitAndTestChunking(CancellationToken c System.Console.WriteLine("TEST: Sending Bridge tests topic..."); - var bridgeTestTopicResult = await topicClient.SendTopic(IPAddress.Loopback, $"tgs_integration_test_tactics2={accessIdentifier}", FindTopicPort(), cancellationToken); + var bridgeTestTopicResult = await SendTestTopic( + $"tgs_integration_test_tactics2={accessIdentifier}", + cancellationToken); Assert.AreEqual("ack2", bridgeTestTopicResult.StringData); await bridgeTestsTcs.Task.WaitAsync(cancellationToken); @@ -902,10 +910,8 @@ async Task ValidateTopicLimits(CancellationToken cancellationToken) try { System.Console.WriteLine($"Topic send limit test S:{currentSize}..."); - topicRequestResult = await topicClient.SendTopic( - IPAddress.Loopback, + topicRequestResult = await SendTestTopic( $"tgs_integration_test_tactics3={topicClient.SanitizeString(JsonConvert.SerializeObject(topic, DMApiConstants.SerializerSettings))}", - FindTopicPort(), cancellationToken); } catch (ArgumentOutOfRangeException) @@ -943,10 +949,8 @@ async Task ValidateTopicLimits(CancellationToken cancellationToken) { var currentSize = baseSize + (int)Math.Pow(2, nextPow); System.Console.WriteLine($"Topic recieve limit test S:{currentSize}..."); - var topicRequestResult = await topicClient.SendTopic( - IPAddress.Loopback, + var topicRequestResult = await SendTestTopic( $"tgs_integration_test_tactics4={topicClient.SanitizeString(currentSize.ToString())}", - FindTopicPort(), cancellationToken); if (topicRequestResult.ResponseType != TopicResponseType.StringResponse @@ -1332,7 +1336,13 @@ public static async Task TellWorldToReboot2(IInstanceClient System.Console.WriteLine("TEST: Sending world reboot topic..."); - var result = await topicClient.SendTopic(IPAddress.Loopback, "tgs_integration_test_special_tactics=1", topicPort, cancellationToken); + var result = await topicClient.SendWithOptionalPriority( + new AsyncDelayer(), + Mock.Of(), + $"tgs_integration_test_special_tactics=1", + topicPort, + true, + cancellationToken); Assert.AreEqual("ack", result.StringData); using var tempCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); @@ -1468,7 +1478,9 @@ async Task CheckDMApiFail(CompileJobResponse compileJob, CancellationToken cance async ValueTask TestLegacyBridgeEndpoint(CancellationToken cancellationToken) { System.Console.WriteLine("TEST: TestLegacyBridgeEndpoint"); - var result = await topicClient.SendTopic(IPAddress.Loopback, "im_out_of_memes=1", FindTopicPort(), cancellationToken); + var result = await SendTestTopic( + "im_out_of_memes=1", + cancellationToken); Assert.IsNotNull(result); Assert.AreEqual("all gucci", result.StringData); await CheckDMApiFail((await instanceClient.DreamDaemon.Read(cancellationToken)).ActiveCompileJob, cancellationToken); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 8aea9eb1eac..a968d57219e 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1532,10 +1532,12 @@ await FailFast( // test the reattach message queueing // for the code coverage really... - var topicRequestResult = await WatchdogTest.StaticTopicClient.SendTopic( - IPAddress.Loopback, + var topicRequestResult = await WatchdogTest.StaticTopicClient.SendWithOptionalPriority( + new AsyncDelayer(), + Mock.Of(), $"tgs_integration_test_tactics6=1", mainDDPort, + true, cancellationToken); Assert.IsNotNull(topicRequestResult); @@ -1608,10 +1610,12 @@ await FailFast( var chatReadTask = instanceClient.ChatBots.List(null, cancellationToken); // Check the DMAPI got the channels again https://github.com/tgstation/tgstation-server/issues/1490 - topicRequestResult = await WatchdogTest.StaticTopicClient.SendTopic( - IPAddress.Loopback, + topicRequestResult = await WatchdogTest.StaticTopicClient.SendWithOptionalPriority( + new AsyncDelayer(), + Mock.Of(), $"tgs_integration_test_tactics7=1", mainDDPort, + true, cancellationToken); Assert.IsNotNull(topicRequestResult); From 15aa09597012625c94675cd41ae06adde761c8d4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 3 Dec 2023 14:11:48 -0500 Subject: [PATCH 406/717] Prominent errored windows tests artifact names --- .github/workflows/ci-pipeline.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 79bc7767198..41d156de2a7 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -564,11 +564,19 @@ jobs: fi - name: Store Live Tests Output + if: ${{ steps.live-tests.outputs.succeeded == 'YES' }} uses: actions/upload-artifact@v3 with: name: windows-integration-test-logs-${{ matrix.configuration }}-${{ matrix.watchdog-type }}-${{ matrix.database-type }} path: ./test_output.txt + - name: Store Errored Live Tests Output + if: ${{ steps.live-tests.outputs.succeeded != 'YES' }} + uses: actions/upload-artifact@v3 + with: + name: errored-windows-test-logs-${{ matrix.configuration }}-${{ matrix.watchdog-type }}-${{ matrix.database-type }} + path: ./test_output.txt + - name: Fail if Live Tests Failed if: ${{ steps.live-tests.outputs.succeeded != 'YES' }} run: exit 1 From d1e26bc37429b94a0f376374d49f73807b970bb4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 3 Dec 2023 14:18:18 -0500 Subject: [PATCH 407/717] Fix dumping multiple times in the same second --- .../Components/Watchdog/WatchdogBase.cs | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index 33961aa1f6e..59aebe0c577 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -447,19 +447,28 @@ public async ValueTask HandleRestart(Version updateVersion, bool handlerMayDelay public async ValueTask CreateDump(CancellationToken cancellationToken) { const string DumpDirectory = "ProcessDumps"; - await diagnosticsIOManager.CreateDirectory(DumpDirectory, cancellationToken); + using (await SemaphoreSlimContext.Lock(synchronizationSemaphore, cancellationToken)) + { + var dumpFileNameTemplate = diagnosticsIOManager.ResolvePath( + diagnosticsIOManager.ConcatPath( + DumpDirectory, + $"DreamDaemon-{DateTimeOffset.UtcNow.ToFileStamp()}.dmp")); - var dumpFileName = diagnosticsIOManager.ResolvePath( - diagnosticsIOManager.ConcatPath( - DumpDirectory, - $"DreamDaemon-{DateTimeOffset.UtcNow.ToFileStamp()}.dmp")); + var dumpFileName = dumpFileNameTemplate; + var iteration = 0; + while (await diagnosticsIOManager.FileExists(dumpFileName, cancellationToken)) + dumpFileName = $"{dumpFileNameTemplate} ({++iteration})"; - var session = GetActiveController(); - if (session?.Lifetime.IsCompleted != false) - throw new JobException(ErrorCode.GameServerOffline); + if (iteration == 0) + await diagnosticsIOManager.CreateDirectory(DumpDirectory, cancellationToken); - Logger.LogInformation("Dumping session to {dumpFileName}...", dumpFileName); - await session.CreateDump(dumpFileName, cancellationToken); + var session = GetActiveController(); + if (session?.Lifetime.IsCompleted != false) + throw new JobException(ErrorCode.GameServerOffline); + + Logger.LogInformation("Dumping session to {dumpFileName}...", dumpFileName); + await session.CreateDump(dumpFileName, cancellationToken); + } } /// From c6ac59529046e4070933266d6cf2624dea21d304 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 3 Dec 2023 14:21:53 -0500 Subject: [PATCH 408/717] Improve an assert --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index e011fcc1783..0668eb4d0a8 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -923,7 +923,11 @@ async Task ValidateTopicLimits(CancellationToken cancellationToken) || topicRequestResult.StringData != "pass") { if (topicRequestResult != null) + { + Assert.AreEqual(TopicResponseType.StringResponse, topicRequestResult.ResponseType, $"String data is: {topicRequestResult.StringData ?? "<>"}"); Assert.AreEqual("fail", topicRequestResult.StringData); + } + if (currentSize == lastSize + 1) break; baseSize = lastSize; From 10188c782fe3ff7504c51c71b0dd50fe425fd4e1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 3 Dec 2023 14:29:38 -0500 Subject: [PATCH 409/717] Hopefully fix bug in JobsHubTest --- .../Live/Instance/JobsHubTests.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index e5f6bd0225c..099877690f2 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -211,13 +211,18 @@ static DateTimeOffset PerformDBTruncation(DateTimeOffset original) static string JobListFormatter(IEnumerable jobs) => String.Join(Environment.NewLine, jobs.Select(x => $"- I:{x.InstanceId}|JID:{x.Id}|JC:{x.JobCode}|Desc:{x.Description}")); + var jobsSeenByHubButNotInAllJobs = seenJobs.Values.Where(x => !allJobs.Any(y => y.Id.Value == x.Id.Value)).ToList(); + // some instances may be detached, but our cache remains var accountedJobs = allJobs.Count - missableMissedJobs; - var accountedSeenJobs = seenJobs.Where(x => allInstances.Any(i => i.Id.Value == x.Value.InstanceId)).ToList(); + var errorMessage = $"Mismatch in seen jobs:{Environment.NewLine}Not seen in seen:{Environment.NewLine}{JobListFormatter(allJobs.Where(x => !seenJobs.Any(y => y.Key == x.Id.Value)))}{Environment.NewLine}Seen not in all:{Environment.NewLine}{JobListFormatter(jobsSeenByHubButNotInAllJobs)}"; Assert.AreEqual( accountedJobs, - accountedSeenJobs.Count, - $"Mismatch in seen jobs:{Environment.NewLine}Not seen in seen:{Environment.NewLine}{JobListFormatter(allJobs.Where(x => !seenJobs.Any(y => y.Key == x.Id.Value)))}{Environment.NewLine}Seen not in all:{Environment.NewLine}{JobListFormatter(seenJobs.Values.Where(x => !allJobs.Any(y => y.Id.Value == x.Id.Value)))}"); + seenJobs.Count - jobsSeenByHubButNotInAllJobs.Count, + errorMessage); + Assert.IsTrue( + jobsSeenByHubButNotInAllJobs.All(job => job.JobCode.Value == JobCode.Move), + errorMessage); Assert.IsTrue(accountedJobs <= seenJobs.Count); Assert.AreNotEqual(0, permlessSeenJobs.Count); Assert.IsTrue(permlessSeenJobs.Count < seenJobs.Count); From 69f4c7e0b69500baf4e94f133864a92aa76ed699 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 3 Dec 2023 14:38:45 -0500 Subject: [PATCH 410/717] Add some diagnostic messages for tests --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 0668eb4d0a8..bdd0180e9c7 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -763,7 +763,9 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke }, cancellationToken); ValidateSessionId(ddStatus, true); + global::System.Console.WriteLine($"WATCHDOG TEST {instanceClient.Metadata.Id}: COMMENCE PROCESS SUSPEND FOR HEALTH CHECK DEATH PID {ourProcessHandler.Id}."); ourProcessHandler.Suspend(); + global::System.Console.WriteLine($"WATCHDOG TEST {instanceClient.Metadata.Id}: FINISH PROCESS SUSPEND FOR HEALTH CHECK DEATH. WAITING FOR LIFETIME {ourProcessHandler.Id}."); await Task.WhenAny(ourProcessHandler.Lifetime, Task.Delay(TimeSpan.FromMinutes(2), cancellationToken)); Assert.IsTrue(ourProcessHandler.Lifetime.IsCompleted); From da78b8e8a15b3cb059bab11f6012e1cebfebf5c8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 3 Dec 2023 14:53:45 -0500 Subject: [PATCH 411/717] Fix deadlock with `DumpOnHealthCheckRestart` --- .../Components/Watchdog/WatchdogBase.cs | 54 +++++++++++-------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index 59aebe0c577..60b3deb05fd 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -446,29 +446,8 @@ public async ValueTask HandleRestart(Version updateVersion, bool handlerMayDelay /// public async ValueTask CreateDump(CancellationToken cancellationToken) { - const string DumpDirectory = "ProcessDumps"; using (await SemaphoreSlimContext.Lock(synchronizationSemaphore, cancellationToken)) - { - var dumpFileNameTemplate = diagnosticsIOManager.ResolvePath( - diagnosticsIOManager.ConcatPath( - DumpDirectory, - $"DreamDaemon-{DateTimeOffset.UtcNow.ToFileStamp()}.dmp")); - - var dumpFileName = dumpFileNameTemplate; - var iteration = 0; - while (await diagnosticsIOManager.FileExists(dumpFileName, cancellationToken)) - dumpFileName = $"{dumpFileNameTemplate} ({++iteration})"; - - if (iteration == 0) - await diagnosticsIOManager.CreateDirectory(DumpDirectory, cancellationToken); - - var session = GetActiveController(); - if (session?.Lifetime.IsCompleted != false) - throw new JobException(ErrorCode.GameServerOffline); - - Logger.LogInformation("Dumping session to {dumpFileName}...", dumpFileName); - await session.CreateDump(dumpFileName, cancellationToken); - } + await CreateDumpNoLock(cancellationToken); } /// @@ -1153,7 +1132,7 @@ async ValueTask HandleHealthCheck(CancellationToken cancellationT Logger.LogDebug("DumpOnHealthCheckRestart enabled."); try { - await CreateDump(cancellationToken); + await CreateDumpNoLock(cancellationToken); } catch (JobException ex) { @@ -1203,5 +1182,34 @@ void HandleChatResponses(TopicResponse result) .Where(nullableChannelId => nullableChannelId.HasValue) .Select(nullableChannelId => nullableChannelId.Value)); } + + /// + /// Attempt to create a process dump for the game server. Requires a lock on . + /// + /// The for the operation. + /// A representing the running operation. + async ValueTask CreateDumpNoLock(CancellationToken cancellationToken) + { + const string DumpDirectory = "ProcessDumps"; + var dumpFileNameTemplate = diagnosticsIOManager.ResolvePath( + diagnosticsIOManager.ConcatPath( + DumpDirectory, + $"DreamDaemon-{DateTimeOffset.UtcNow.ToFileStamp()}.dmp")); + + var dumpFileName = dumpFileNameTemplate; + var iteration = 0; + while (await diagnosticsIOManager.FileExists(dumpFileName, cancellationToken)) + dumpFileName = $"{dumpFileNameTemplate} ({++iteration})"; + + if (iteration == 0) + await diagnosticsIOManager.CreateDirectory(DumpDirectory, cancellationToken); + + var session = GetActiveController(); + if (session?.Lifetime.IsCompleted != false) + throw new JobException(ErrorCode.GameServerOffline); + + Logger.LogInformation("Dumping session to {dumpFileName}...", dumpFileName); + await session.CreateDump(dumpFileName, cancellationToken); + } } } From 6d6645e9a20697d13d3dfa1b5dcf1d0fa3a357b4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 4 Dec 2023 22:25:06 -0500 Subject: [PATCH 412/717] Add a diagnostic message to an `Assert` --- tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index 099877690f2..17fb4c0d89b 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -204,7 +204,7 @@ static DateTimeOffset PerformDBTruncation(DateTimeOffset original) var wasMissableJob = job.JobCode == JobCode.ReconnectChatBot || job.JobCode == JobCode.StartupWatchdogLaunch || job.JobCode == JobCode.StartupWatchdogReattach; - Assert.IsTrue(wasMissableJob); + Assert.IsTrue(wasMissableJob, $"Found unexpected missed job: {job.Description}"); ++missableMissedJobs; } } From 081b8d19a6e2ea5d7dfdce03a3c5a90ed5dd9849 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 4 Dec 2023 22:26:59 -0500 Subject: [PATCH 413/717] Assert that the process is running before the Linux links test --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index bdd0180e9c7..576d025fef3 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -680,7 +680,9 @@ void TestLinuxIsntBeingFuckingCheekyAboutFilePaths(DreamDaemonResponse currentSt var pid = proc.Id; var foundLivePath = false; var allPaths = new List(); - foreach (var fd in Directory.EnumerateFiles($"/proc/{pid}/fd")) + + Assert.IsFalse(proc.HasExited); + foreach (var fd in Directory.GetFiles($"/proc/{pid}/fd")) { var sb = new StringBuilder(UInt16.MaxValue); if (Syscall.readlink(fd, sb) == -1) From 711c04bc03c5a251ea84b2eb256291443c7ed5b7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 12 Dec 2023 10:55:04 -0500 Subject: [PATCH 414/717] Update Nuget packages --- build/NugetCommon.props | 2 +- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/NugetCommon.props b/build/NugetCommon.props index d1c341efd00..f07a00a656b 100644 --- a/build/NugetCommon.props +++ b/build/NugetCommon.props @@ -25,7 +25,7 @@ - + diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 5be73fa4ee7..04f82f6b2d4 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -107,7 +107,7 @@ - + @@ -125,7 +125,7 @@ - + From 5231bd8a816a91595c5d50a91f33d80f914fa296 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 13 Dec 2023 21:49:22 -0500 Subject: [PATCH 415/717] Update to LibGit2Sharp 0.29.0 --- .../Components/Repository/Repository.cs | 76 ++++------------ .../Repository/RepositoryManager.cs | 21 ++--- .../Extensions/FetchOptionsExtensions.cs | 91 +++++++++++++++++++ .../Tgstation.Server.Host.csproj | 2 +- .../Repository/TestRepositoryFactory.cs | 9 +- 5 files changed, 122 insertions(+), 77 deletions(-) create mode 100644 src/Tgstation.Server.Host/Extensions/FetchOptionsExtensions.cs diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs index a3b81d2bad7..125ceded308 100644 --- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs @@ -247,20 +247,16 @@ await Task.Factory.StartNew( libGitRepo, refSpecList, remote, - new FetchOptions - { - Prune = true, - OnProgress = (a) => !cancellationToken.IsCancellationRequested, - OnTransferProgress = TransferProgressHandler( - progressReporter.CreateSection($"Fetch {refSpec}", progressFactor), - cancellationToken), - OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested, - CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password), - }, + new FetchOptions().Hydrate( + logger, + progressReporter.CreateSection($"Fetch {refSpec}", progressFactor), + credentialsProvider.GenerateCredentialsHandler(username, password), + cancellationToken), logMessage); } - catch (UserCancelledException) + catch (UserCancelledException ex) { + logger.LogTrace(ex, "Suppressing fetch cancel exception"); } catch (LibGit2SharpException ex) { @@ -439,14 +435,12 @@ await Task.Factory.StartNew( var fetchOptions = new FetchOptions { Prune = true, - OnProgress = (a) => !cancellationToken.IsCancellationRequested, - OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested, - CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password), TagFetchMode = TagFetchMode.All, - }; - - if (progressReporter != null) - fetchOptions.OnTransferProgress = TransferProgressHandler(progressReporter.CreateSection("Fetch Origin", 1.0), cancellationToken); + }.Hydrate( + logger, + progressReporter?.CreateSection("Fetch Origin", 1.0), + credentialsProvider.GenerateCredentialsHandler(username, password), + cancellationToken); commands.Fetch( libGitRepo, @@ -1041,19 +1035,18 @@ async ValueTask UpdateSubmodules( var submoduleUpdateOptions = new SubmoduleUpdateOptions { Init = true, - OnProgress = output => !cancellationToken.IsCancellationRequested, - OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested, - CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password), + OnCheckoutNotify = (_, _) => !cancellationToken.IsCancellationRequested, }; + submoduleUpdateOptions.FetchOptions.Hydrate( + logger, + progressReporter?.CreateSection($"Fetch submodule {submodule.Name}", factor), + credentialsProvider.GenerateCredentialsHandler(username, password), + cancellationToken); + if (progressReporter != null) - { - submoduleUpdateOptions.OnTransferProgress = TransferProgressHandler( - progressReporter.CreateSection($"Fetch submodule {submodule.Name}", factor), - cancellationToken); submoduleUpdateOptions.OnCheckoutProgress = CheckoutProgressHandler( progressReporter.CreateSection($"Checkout submodule {submodule.Name}", factor)); - } logger.LogDebug("Updating submodule {submoduleName}...", submodule.Name); Task RawSubModuleUpdate() => Task.Factory.StartNew( @@ -1131,37 +1124,6 @@ CheckoutProgressHandler CheckoutProgressHandler(JobProgressReporter progressRepo progressReporter.ReportProgress(percentage); }; - - /// - /// Generate a from a given and . - /// - /// The of the operation. - /// The for the operation. - /// A new based on . - TransferProgressHandler TransferProgressHandler(JobProgressReporter progressReporter, CancellationToken cancellationToken) => (transferProgress) => - { - double? percentage; - var totalObjectsToProcess = transferProgress.TotalObjects * 2; - var processedObjects = transferProgress.IndexedObjects + transferProgress.ReceivedObjects; - if (totalObjectsToProcess < processedObjects || totalObjectsToProcess == 0) - percentage = null; - else - { - percentage = (double)processedObjects / totalObjectsToProcess; - if (percentage < 0) - percentage = null; - } - - if (percentage == null) - logger.LogDebug( - "Bad transfer progress values (Please tell Cyberboss)! Indexed: {indexed}, Received: {received}, Total: {total}", - transferProgress.IndexedObjects, - transferProgress.ReceivedObjects, - transferProgress.TotalObjects); - - progressReporter.ReportProgress(percentage); - return !cancellationToken.IsCancellationRequested; - }; } #pragma warning restore CA1506 } diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs index 5852a58f972..8ce9b603181 100644 --- a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs +++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs @@ -9,6 +9,7 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.Configuration; +using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; @@ -149,20 +150,7 @@ public async ValueTask CloneRepository( var checkoutProgressReporter = progressReporter?.CreateSection(null, 0.25f); var cloneOptions = new CloneOptions { - OnProgress = (a) => !cancellationToken.IsCancellationRequested, - OnTransferProgress = (a) => - { - if (cloneProgressReporter != null) - { - var percentage = ((double)a.IndexedObjects + a.ReceivedObjects) / (a.TotalObjects * 2); - cloneProgressReporter.ReportProgress(percentage); - } - - return !cancellationToken.IsCancellationRequested; - }, RecurseSubmodules = recurseSubmodules, - OnUpdateTips = (a, b, c) => !cancellationToken.IsCancellationRequested, - RepositoryOperationStarting = (a) => !cancellationToken.IsCancellationRequested, OnCheckoutProgress = (path, completed, remaining) => { if (checkoutProgressReporter == null) @@ -172,9 +160,14 @@ public async ValueTask CloneRepository( checkoutProgressReporter.ReportProgress(percentage); }, BranchName = initialBranch, - CredentialsProvider = repositoryFactory.GenerateCredentialsHandler(username, password), }; + cloneOptions.FetchOptions.Hydrate( + logger, + cloneProgressReporter, + repositoryFactory.GenerateCredentialsHandler(username, password), + cancellationToken); + await repositoryFactory.Clone( url, cloneOptions, diff --git a/src/Tgstation.Server.Host/Extensions/FetchOptionsExtensions.cs b/src/Tgstation.Server.Host/Extensions/FetchOptionsExtensions.cs new file mode 100644 index 00000000000..e1b47d644a5 --- /dev/null +++ b/src/Tgstation.Server.Host/Extensions/FetchOptionsExtensions.cs @@ -0,0 +1,91 @@ +using System; +using System.Threading; + +using LibGit2Sharp; +using LibGit2Sharp.Handlers; + +using Microsoft.Extensions.Logging; + +using Tgstation.Server.Host.Jobs; + +namespace Tgstation.Server.Host.Extensions +{ + /// + /// Extension methods for . + /// + static class FetchOptionsExtensions + { + /// + /// Hydrate a given set of . + /// + /// The to hydrate. + /// The for the operation. + /// The optional . + /// The optional . + /// The for the operation. + /// The hydrated . + public static FetchOptions Hydrate( + this FetchOptions fetchOptions, + ILogger logger, + JobProgressReporter progressReporter, + CredentialsHandler credentialsHandler, + CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(fetchOptions); + ArgumentNullException.ThrowIfNull(logger); + + fetchOptions.OnProgress = _ => !cancellationToken.IsCancellationRequested; + fetchOptions.OnTransferProgress = transferProgress => + { + if (progressReporter != null) + { + var percentage = ((double)transferProgress.IndexedObjects + transferProgress.ReceivedObjects) / (transferProgress.TotalObjects * 2); + progressReporter.ReportProgress(percentage); + } + + return !cancellationToken.IsCancellationRequested; + }; + fetchOptions.OnUpdateTips = (_, _, _) => !cancellationToken.IsCancellationRequested; + fetchOptions.CredentialsProvider = credentialsHandler; + fetchOptions.RepositoryOperationStarting = _ => !cancellationToken.IsCancellationRequested; + fetchOptions.OnTransferProgress = TransferProgressHandler( + logger, + progressReporter, + cancellationToken); + + return fetchOptions; + } + + /// + /// Generate a from a given and . + /// + /// The for the operation. + /// The optional of the operation. + /// The for the operation. + /// A new based on . + static TransferProgressHandler TransferProgressHandler(ILogger logger, JobProgressReporter progressReporter, CancellationToken cancellationToken) => transferProgress => + { + double? percentage; + var totalObjectsToProcess = transferProgress.TotalObjects * 2; + var processedObjects = transferProgress.IndexedObjects + transferProgress.ReceivedObjects; + if (totalObjectsToProcess < processedObjects || totalObjectsToProcess == 0) + percentage = null; + else + { + percentage = (double)processedObjects / totalObjectsToProcess; + if (percentage < 0) + percentage = null; + } + + if (percentage == null) + logger.LogDebug( + "Bad transfer progress values (Please tell Cyberboss)! Indexed: {indexed}, Received: {received}, Total: {total}", + transferProgress.IndexedObjects, + transferProgress.ReceivedObjects, + transferProgress.TotalObjects); + + progressReporter?.ReportProgress(percentage); + return !cancellationToken.IsCancellationRequested; + }; + } +} diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 04f82f6b2d4..af8a133ea0c 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -73,7 +73,7 @@ - + diff --git a/tests/Tgstation.Server.Host.Tests/Components/Repository/TestRepositoryFactory.cs b/tests/Tgstation.Server.Host.Tests/Components/Repository/TestRepositoryFactory.cs index bbf369efcea..04e7cdb66bd 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Repository/TestRepositoryFactory.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Repository/TestRepositoryFactory.cs @@ -1,4 +1,4 @@ -using LibGit2Sharp; +using LibGit2Sharp; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -39,12 +39,11 @@ public async Task TestCloning() try { var factory = CreateFactory(); + var cloneOpts = new CloneOptions(); + cloneOpts.FetchOptions.CredentialsProvider = factory.GenerateCredentialsHandler(null, null); await factory.Clone( new Uri("https://github.com/Cyberboss/Test"), - new CloneOptions - { - CredentialsProvider = factory.GenerateCredentialsHandler(null, null) - }, + cloneOpts, tempDir, default); From ef0bf6c0cf54356d90485fbdb5154fe7a9f0b0c2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 13 Dec 2023 22:59:50 -0500 Subject: [PATCH 416/717] Force this variable to check for `true` --- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index a968d57219e..52b0b3f90e0 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1213,7 +1213,7 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest [TestMethod] public Task TestOpenDreamExclusiveTgsOperation() { - if (String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS_TEST_OD_EXCLUSIVE"))) + if (Environment.GetEnvironmentVariable("TGS_TEST_OD_EXCLUSIVE") != "true") Assert.Inconclusive("This test is covered by TestStandardTgsOperation"); return TestStandardTgsOperation(true); From 7af656d3d53d1814b9402aadb472416ab8f432a6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 13 Dec 2023 23:00:14 -0500 Subject: [PATCH 417/717] Some better test crash diagnostics --- tests/Tgstation.Server.Tests/TestSystemInteraction.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Tgstation.Server.Tests/TestSystemInteraction.cs b/tests/Tgstation.Server.Tests/TestSystemInteraction.cs index 1075b698d3e..4570c58b947 100644 --- a/tests/Tgstation.Server.Tests/TestSystemInteraction.cs +++ b/tests/Tgstation.Server.Tests/TestSystemInteraction.cs @@ -69,12 +69,12 @@ public async Task TestScriptExecutionWithFileOutput() Assert.AreEqual(0, exitCode); } - Assert.IsTrue(File.Exists(tempFile)); + Assert.IsTrue(File.Exists(tempFile), $"Could not find temp file: {tempFile}"); var result = File.ReadAllText(tempFile).Trim(); // no guarantees about order - Assert.IsTrue(result.Contains("Hello World!")); - Assert.IsTrue(result.Contains("Hello Error!")); + Assert.IsTrue(result.Contains("Hello World!"), $"Result: {result}"); + Assert.IsTrue(result.Contains("Hello Error!"), $"Result: {result}"); } finally { From be29aa0a8e55286d489160dc1c8d03b2e81184d0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 14 Dec 2023 17:42:35 -0500 Subject: [PATCH 418/717] Nullify `ChannelMapping` --- .../Components/Chat/ChannelMapping.cs | 13 +++++++++++-- .../Components/Chat/ChatManager.cs | 8 +++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs b/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs index 8773e402a96..19581b09bbb 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs @@ -1,4 +1,4 @@ -#nullable disable +using System; namespace Tgstation.Server.Host.Components.Chat { @@ -40,6 +40,15 @@ sealed class ChannelMapping /// /// The with the mapped Id. /// - public ChannelRepresentation Channel { get; set; } + public ChannelRepresentation Channel { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + public ChannelMapping(ChannelRepresentation channel) + { + Channel = channel ?? throw new ArgumentNullException(nameof(channel)); + } } } diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index 409c6555c24..44e6625691b 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -71,7 +71,7 @@ sealed class ChatManager : IChatManager, IRestartHandler readonly Dictionary providers; /// - /// Map of s used to guard concurrent access to , keyed by . + /// Map of s used to guard concurrent access to , keyed by . /// readonly ConcurrentDictionary changeChannelSemaphores; @@ -236,7 +236,7 @@ public async ValueTask ChangeChannels(long connectionId, IEnumerable kvp.Value.Select( - channelRepresentation => new ChannelMapping + channelRepresentation => new ChannelMapping(channelRepresentation) { IsWatchdogChannel = kvp.Key.IsWatchdogChannel == true, IsUpdatesChannel = kvp.Key.IsUpdatesChannel == true, @@ -244,7 +244,6 @@ public async ValueTask ChangeChannels(long connectionId, IEnumerable SendMessage( message.User.Channel.ConnectionName, message.User.FriendlyName, newId); - mappedChannels.Add(newId, new ChannelMapping + mappedChannels.Add(newId, new ChannelMapping(message.User.Channel) { ProviderChannelId = message.User.Channel.RealId, ProviderId = providerId, - Channel = message.User.Channel, }); logger.LogTrace( From 4f63b9619b4b2f2f4103e3325a35803c09f7707c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 14 Dec 2023 17:48:16 -0500 Subject: [PATCH 419/717] Add some whitespace --- .../Components/Session/TopicClientFactory.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs b/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs index 40605e5de8e..29768e76041 100644 --- a/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs @@ -1,6 +1,7 @@ using System; using Byond.TopicSender; + using Microsoft.Extensions.Logging; namespace Tgstation.Server.Host.Components.Session From 3921e60dc70f4921dcdafacc5045989da9135202 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 14 Dec 2023 22:42:14 -0500 Subject: [PATCH 420/717] Add a log line --- .../Components/Watchdog/AdvancedWatchdog.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs index 33140b9e575..4495a99fe3a 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs @@ -395,6 +395,7 @@ async ValueTask PerformDmbSwap(SwappableDmbProvider newProvider, CancellationTok try { + Logger.LogTrace("Making new provider {id} active...", newProvider.CompileJob.Id); await newProvider.MakeActive(cancellationToken); } finally From 7b3fa4a53cf9dab6e2c73779ce23d62ecefef452 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 14 Dec 2023 23:10:12 -0500 Subject: [PATCH 421/717] Some additional test diagnostics --- .../Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 576d025fef3..8fcccf05892 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -18,6 +18,7 @@ using System.Net; using System.Net.Sockets; using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading; @@ -1334,15 +1335,15 @@ bool KillDD(bool require) return ddProc != null; } - public Task TellWorldToReboot(bool waitForOnlineIfRestoring, CancellationToken cancellationToken) - => TellWorldToReboot2(instanceClient, topicClient, FindTopicPort(), waitForOnlineIfRestoring || testVersion.Engine.Value == EngineType.OpenDream, cancellationToken); - public static async Task TellWorldToReboot2(IInstanceClient instanceClient, ITopicClient topicClient, ushort topicPort, bool waitForOnlineIfRestoring, CancellationToken cancellationToken) + public Task TellWorldToReboot(bool waitForOnlineIfRestoring, CancellationToken cancellationToken, [CallerLineNumber]int source = 0) + => TellWorldToReboot2(instanceClient, topicClient, FindTopicPort(), waitForOnlineIfRestoring || testVersion.Engine.Value == EngineType.OpenDream, cancellationToken, source); + public static async Task TellWorldToReboot2(IInstanceClient instanceClient, ITopicClient topicClient, ushort topicPort, bool waitForOnlineIfRestoring, CancellationToken cancellationToken, [CallerLineNumber]int source = 0, [CallerFilePath]string path = null) { var daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.IsNotNull(daemonStatus.StagedCompileJob); var initialSession = daemonStatus.ActiveCompileJob; - System.Console.WriteLine("TEST: Sending world reboot topic..."); + System.Console.WriteLine($"TEST: Sending world reboot topic @ {path}#L{source}"); var result = await topicClient.SendWithOptionalPriority( new AsyncDelayer(), From ea1fecb4fd547c1be9e3b622427e19534e34e0bd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 14 Dec 2023 23:11:25 -0500 Subject: [PATCH 422/717] Update `Byond.TopicSender` to v7.1.0 --- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index af8a133ea0c..448d0400176 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -63,7 +63,7 @@ - + @@ -129,6 +129,7 @@ + From dc08e87be0eed7d84a4971acc18025a27915bb54 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 14 Dec 2023 23:21:20 -0500 Subject: [PATCH 423/717] Minor diagnostics for this flaky test --- tests/Tgstation.Server.Tests/TestSystemInteraction.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/Tgstation.Server.Tests/TestSystemInteraction.cs b/tests/Tgstation.Server.Tests/TestSystemInteraction.cs index 4570c58b947..45a017a9680 100644 --- a/tests/Tgstation.Server.Tests/TestSystemInteraction.cs +++ b/tests/Tgstation.Server.Tests/TestSystemInteraction.cs @@ -45,13 +45,17 @@ public async Task TestScriptExecutionWithStdRead() [TestMethod] public async Task TestScriptExecutionWithFileOutput() { - using var loggerFactory = LoggerFactory.Create(x => { }); + using var loggerFactory = LoggerFactory.Create(builder => + { + builder.AddConsole(); + builder.SetMinimumLevel(LogLevel.Trace); + }); var platformIdentifier = new PlatformIdentifier(); var processExecutor = new ProcessExecutor( Mock.Of(), Mock.Of(), new DefaultIOManager(), - Mock.Of>(), + loggerFactory.CreateLogger(), loggerFactory); var tempFile = Path.GetTempFileName(); From 7304cf1a8d2f273a22521684f2e9c51874b8b0fe Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 15 Dec 2023 16:18:02 -0500 Subject: [PATCH 424/717] Clean up the JobsHubTest assertions again --- tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index 17fb4c0d89b..2a7587d43dd 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -215,7 +215,7 @@ static DateTimeOffset PerformDBTruncation(DateTimeOffset original) // some instances may be detached, but our cache remains var accountedJobs = allJobs.Count - missableMissedJobs; - var errorMessage = $"Mismatch in seen jobs:{Environment.NewLine}Not seen in seen:{Environment.NewLine}{JobListFormatter(allJobs.Where(x => !seenJobs.Any(y => y.Key == x.Id.Value)))}{Environment.NewLine}Seen not in all:{Environment.NewLine}{JobListFormatter(jobsSeenByHubButNotInAllJobs)}"; + var errorMessage = $"Mismatch in seen jobs:{Environment.NewLine}Not seen in seen:{Environment.NewLine}{JobListFormatter(allJobs.Where(x => !seenJobs.Any(y => y.Key == x.Id.Value)))}{Environment.NewLine}Seen not in all:{Environment.NewLine}{JobListFormatter(jobsSeenByHubButNotInAllJobs)}{Environment.NewLine}Current Instances: {String.Join(", ", allInstances.Select(i => i.Id.Value))}"; Assert.AreEqual( accountedJobs, seenJobs.Count - jobsSeenByHubButNotInAllJobs.Count, From d932b7e943974a79d334098f20ffe7f0426c7cac Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 15 Dec 2023 19:40:27 -0500 Subject: [PATCH 425/717] Revert "Fold Code Scanning into CI Pipeline" This reverts commit 9ba8952809a8a6f3c11ac05ed7c2f00d84010a33. --- .github/workflows/ci-pipeline.yml | 34 +----------------- .github/workflows/code-scanning.yml | 55 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 33 deletions(-) create mode 100644 .github/workflows/code-scanning.yml diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 41d156de2a7..4f5a0f95d26 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -83,38 +83,6 @@ jobs: - name: GitHub Requires at Least One Step for a Job run: exit 0 - analyze: - name: Code Scanning - needs: start-ci-run-gate - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - if: (!(cancelled() || failure()) && needs.start-ci-run-gate.result == 'success' && ${{ vars.TGS_ENABLE_CODE_QL }} == 'true') - steps: - - name: Setup dotnet - uses: actions/setup-dotnet@v3 - with: - dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' - dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - - - name: Checkout - uses: actions/checkout@v3 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: csharp - - - name: Build - run: dotnet build -c ReleaseNoWindows -p:TGS_HOST_NO_WEBPANEL=true - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: "/language:csharp" - dmapi-build: name: Build DMAPI needs: start-ci-run-gate @@ -1355,7 +1323,7 @@ jobs: ci-completion-gate: # This job exists so there isn't a moving target for branch protections name: CI Completion Gate - needs: [ pages-build, docker-build, build-deb, build-msi, validate-openapi-spec, upload-code-coverage, check-winget-pr-template, analyze ] + needs: [ pages-build, docker-build, build-deb, build-msi, validate-openapi-spec, upload-code-coverage, check-winget-pr-template ] runs-on: ubuntu-latest if: (!(cancelled() || failure()) && needs.pages-build.result == 'success' && needs.docker-build.result == 'success' && needs.build-deb.result == 'success' && needs.build-msi.result == 'success' && needs.validate-openapi-spec.result == 'success' && needs.upload-code-coverage.result == 'success' && needs.check-winget-pr-template.result == 'success') steps: diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml new file mode 100644 index 00000000000..9442ce55308 --- /dev/null +++ b/.github/workflows/code-scanning.yml @@ -0,0 +1,55 @@ +name: 'Code Scanning' + +on: + schedule: + - cron: 0 23 * * 1 + push: + branches: + - dev + - master + - V6 + pull_request: + branches: + - dev + - master + - V6 + +env: + TGS_DOTNET_VERSION: 8 + TGS_DOTNET_QUALITY: ga + +concurrency: + group: "code-scanning-${{ github.head_ref || github.run_id }}-${{ github.event_name }}" + cancel-in-progress: true + +jobs: + analyze: + name: Code Scanning + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + if: ${{ vars.TGS_ENABLE_CODE_QL }} == 'true' + steps: + - name: Setup dotnet + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x' + dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} + + - name: Checkout + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: csharp + + - name: Build + run: dotnet build -c ReleaseNoWindows -p:TGS_HOST_NO_WEBPANEL=true + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:csharp" From 198f0f714ffa71c98bc9e672ce5bee94b024d054 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 15 Dec 2023 19:41:22 -0500 Subject: [PATCH 426/717] Remove code scanning cron --- .github/workflows/code-scanning.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml index 9442ce55308..a0e8069a33e 100644 --- a/.github/workflows/code-scanning.yml +++ b/.github/workflows/code-scanning.yml @@ -1,8 +1,6 @@ name: 'Code Scanning' on: - schedule: - - cron: 0 23 * * 1 push: branches: - dev From e0f67bb6dff432ea213b4bf572c5e4611bce00f7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 15 Dec 2023 19:50:05 -0500 Subject: [PATCH 427/717] More `JobsHubTests` diagnostics --- tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index 2a7587d43dd..8b8de95ffe5 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -169,6 +169,11 @@ await permedUser.Instances.Update(new InstanceUpdateRequest .Select(CheckInstance); var allJobs = (await ValueTaskExtensions.WhenAll(allJobsTask, allInstances.Count)).SelectMany(x => x).ToList(); + + var uniqueAllJobs = allJobs.GroupBy(x => x.Id.Value).Select(x => x.First()).ToList(); + + Assert.AreEqual(allJobs.Count, uniqueAllJobs.Count); + var missableMissedJobs = 0; foreach (var job in allJobs) { @@ -204,7 +209,7 @@ static DateTimeOffset PerformDBTruncation(DateTimeOffset original) var wasMissableJob = job.JobCode == JobCode.ReconnectChatBot || job.JobCode == JobCode.StartupWatchdogLaunch || job.JobCode == JobCode.StartupWatchdogReattach; - Assert.IsTrue(wasMissableJob, $"Found unexpected missed job: {job.Description}"); + Assert.IsTrue(wasMissableJob, $"Found unexpected missed job: #{job.Id.Value} - {job.JobCode} - {job.Description}"); ++missableMissedJobs; } } From 92cc9e7f6a3633a9763ade683bf0955cd12d2ee6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 15 Dec 2023 22:09:12 -0500 Subject: [PATCH 428/717] More diagnostic asserts --- .../Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index 8b8de95ffe5..013de8ea714 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -170,9 +170,11 @@ await permedUser.Instances.Update(new InstanceUpdateRequest var allJobs = (await ValueTaskExtensions.WhenAll(allJobsTask, allInstances.Count)).SelectMany(x => x).ToList(); - var uniqueAllJobs = allJobs.GroupBy(x => x.Id.Value).Select(x => x.First()).ToList(); + var groups = allJobs.GroupBy(x => x.Id.Value).ToList(); + var uniqueAllJobs = groups.Select(x => x.First()).ToList(); - Assert.AreEqual(allJobs.Count, uniqueAllJobs.Count); + static string JobListFormatter(IEnumerable jobs) => String.Join(Environment.NewLine, jobs.Select(x => $"- I:{x.InstanceId}|JID:{x.Id}|JC:{x.JobCode}|Desc:{x.Description}")); + Assert.AreEqual(allJobs.Count, uniqueAllJobs.Count, $"Duplicated Jobs:{Environment.NewLine}{JobListFormatter(groups.Where(x => x.Count() > 1).Select(x => x.First()))}"); var missableMissedJobs = 0; foreach (var job in allJobs) @@ -214,8 +216,6 @@ static DateTimeOffset PerformDBTruncation(DateTimeOffset original) } } - static string JobListFormatter(IEnumerable jobs) => String.Join(Environment.NewLine, jobs.Select(x => $"- I:{x.InstanceId}|JID:{x.Id}|JC:{x.JobCode}|Desc:{x.Description}")); - var jobsSeenByHubButNotInAllJobs = seenJobs.Values.Where(x => !allJobs.Any(y => y.Id.Value == x.Id.Value)).ToList(); // some instances may be detached, but our cache remains From 1665d564d245050ecc5fa5211234755ff79e63e2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 09:21:33 -0500 Subject: [PATCH 429/717] Use proper TCS method --- tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index 013de8ea714..6f578ed6d7e 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -66,7 +66,7 @@ public Task ReceiveJobUpdate(JobResponse job, CancellationToken cancellationToke } catch(Exception ex) { - finishTcs.SetException(ex); + finishTcs.TrySetException(ex); } return Task.CompletedTask; From ba454f0ac05dd3b80429596a1c7e563610c0e98c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 09:22:12 -0500 Subject: [PATCH 430/717] Add a missing throw --- tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index 6f578ed6d7e..8f42d165d4b 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -115,6 +115,7 @@ public async Task Run(CancellationToken cancellationToken) catch { await permedConn.DisposeAsync(); + throw; } return FinishAsync(cancellationToken); From aa51b67ea1f767acced1958022d4891e4ede8648 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 10:07:18 -0500 Subject: [PATCH 431/717] Handle startup jobs a bit better --- .../Extensions/JobCodeExtensions.cs | 25 +++++++++++++++++++ src/Tgstation.Server.Host/Jobs/JobService.cs | 8 +++++- .../Live/Instance/JobsHubTests.cs | 7 +++--- .../Live/TestLiveServer.cs | 18 ++++++------- 4 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 src/Tgstation.Server.Api/Extensions/JobCodeExtensions.cs diff --git a/src/Tgstation.Server.Api/Extensions/JobCodeExtensions.cs b/src/Tgstation.Server.Api/Extensions/JobCodeExtensions.cs new file mode 100644 index 00000000000..90c379f8245 --- /dev/null +++ b/src/Tgstation.Server.Api/Extensions/JobCodeExtensions.cs @@ -0,0 +1,25 @@ +using System; + +using Tgstation.Server.Api.Models; + +namespace Tgstation.Server.Api.Extensions +{ + /// + /// Extension methods for the . + /// + public static class JobCodeExtensions + { + /// + /// If a given can be triggered by TGS startup. + /// + /// The . + /// if the can trigger before startup, otherwise. + public static bool IsServerStartupJob(this JobCode jobCode) + => jobCode switch + { + JobCode.Unknown or JobCode.Move or JobCode.RepositoryClone or JobCode.RepositoryUpdate or JobCode.RepositoryAutoUpdate or JobCode.RepositoryDelete or JobCode.EngineOfficialInstall or JobCode.EngineCustomInstall or JobCode.EngineDelete or JobCode.Deployment or JobCode.AutomaticDeployment or JobCode.WatchdogLaunch or JobCode.WatchdogRestart or JobCode.WatchdogDump => false, + JobCode.StartupWatchdogLaunch or JobCode.StartupWatchdogReattach or JobCode.ReconnectChatBot => true, + _ => throw new InvalidOperationException($"Invalid JobCode: {jobCode}"), + }; + } +} diff --git a/src/Tgstation.Server.Host/Jobs/JobService.cs b/src/Tgstation.Server.Host/Jobs/JobService.cs index 87387c60a93..abdb26170cf 100644 --- a/src/Tgstation.Server.Host/Jobs/JobService.cs +++ b/src/Tgstation.Server.Host/Jobs/JobService.cs @@ -11,6 +11,7 @@ using Serilog.Context; +using Tgstation.Server.Api.Extensions; using Tgstation.Server.Api.Hubs; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Common.Extensions; @@ -452,7 +453,12 @@ void UpdateProgress(string stage, double? progress) } } - var instanceCoreProvider = await activationTcs.Task.WaitAsync(cancellationToken); + var activationTask = activationTcs.Task; + + Debug.Assert(activationTask.IsCompleted || job.JobCode.Value.IsServerStartupJob(), "Non-server startup job registered before activation!"); + + var instanceCoreProvider = await activationTask.WaitAsync(cancellationToken); + QueueHubUpdate(job.ToApi(), false); logger.LogTrace("Starting job..."); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index 8f42d165d4b..19be3fe30b5 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.SignalR.Client; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Tgstation.Server.Api.Extensions; using Tgstation.Server.Api.Hubs; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Request; @@ -209,9 +210,7 @@ static DateTimeOffset PerformDBTruncation(DateTimeOffset original) } else { - var wasMissableJob = job.JobCode == JobCode.ReconnectChatBot - || job.JobCode == JobCode.StartupWatchdogLaunch - || job.JobCode == JobCode.StartupWatchdogReattach; + var wasMissableJob = job.JobCode.Value.IsServerStartupJob(); Assert.IsTrue(wasMissableJob, $"Found unexpected missed job: #{job.Id.Value} - {job.JobCode} - {job.Description}"); ++missableMissedJobs; } diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 52b0b3f90e0..5707027a920 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -28,6 +28,7 @@ using Npgsql; using Tgstation.Server.Api; +using Tgstation.Server.Api.Extensions; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; @@ -1653,16 +1654,11 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) { var jobs = await instanceClient.Jobs.ListActive(null, cancellationToken); if (jobs.Count == 0) - { - var entities = await instanceClient.Jobs.List(null, cancellationToken); - var getTasks = entities - .Select(e => instanceClient.Jobs.GetId(e, cancellationToken)) - .ToList(); - - jobs = (await ValueTaskExtensions.WhenAll(getTasks)) + jobs = (await instanceClient.Jobs.List(null, cancellationToken)) .Where(x => x.StartedAt.Value > preStartupTime) - .ToList(); - } + .ToList(); + else + jobs = jobs.Where(x => x.JobCode.Value.IsServerStartupJob()).ToList(); await using var jrt = new JobsRequiredTest(instanceClient.Jobs); foreach (var job in jobs) @@ -1679,9 +1675,9 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) var edgeVersion = await EngineTest.GetEdgeVersion(EngineType.Byond, fileDownloader, cancellationToken); await using (var adminClient = await CreateAdminClient(server.ApiUrl, cancellationToken)) { + await jobsHubTest.WaitForReconnect(cancellationToken); var instanceClient = adminClient.Instances.CreateClient(instance); await WaitForInitialJobs(instanceClient); - await jobsHubTest.WaitForReconnect(cancellationToken); var dd = await instanceClient.DreamDaemon.Read(cancellationToken); @@ -1722,9 +1718,9 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest serverTask = server.Run(cancellationToken).AsTask(); await using (var adminClient = await CreateAdminClient(server.ApiUrl, cancellationToken)) { + await jobsHubTest.WaitForReconnect(cancellationToken); var instanceClient = adminClient.Instances.CreateClient(instance); await WaitForInitialJobs(instanceClient); - await jobsHubTest.WaitForReconnect(cancellationToken); var currentDD = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.AreEqual(expectedCompileJobId, currentDD.ActiveCompileJob.Id.Value); From e6bc0c9105ad43d97194e1684ce9f74c74089953 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 10:07:56 -0500 Subject: [PATCH 432/717] Disable primary constructor recommendation --- build/analyzers.ruleset | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/build/analyzers.ruleset b/build/analyzers.ruleset index 034747c1386..237aa86fe45 100644 --- a/build/analyzers.ruleset +++ b/build/analyzers.ruleset @@ -1,4 +1,4 @@ - + @@ -88,7 +88,6 @@ - @@ -666,6 +665,10 @@ + + + + @@ -751,6 +754,7 @@ + @@ -1026,8 +1030,6 @@ - - @@ -1043,4 +1045,4 @@ - + \ No newline at end of file From feca232b933962a55c43099c02fdcab1f9499aad Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 10:14:22 -0500 Subject: [PATCH 433/717] Update `Byond.TopicSender` to `8.0.0` --- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 448d0400176..6d50031a8d5 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -63,7 +63,7 @@ - + From f4d33747b5174928e3f66e889363a13d69344e7c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 10:15:10 -0500 Subject: [PATCH 434/717] Update Z.EntityFramework.Plus to `8.101.1.2` --- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 6d50031a8d5..6a2262dfa42 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -125,7 +125,7 @@ - + From 8ab50abef61c8f03b96045fea6d6a73fbba73b07 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 10:27:53 -0500 Subject: [PATCH 435/717] Fix a message --- .../System/ProcessExecutor.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index f6218f5cd9b..acea2604ffa 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -125,13 +125,19 @@ public IProcess LaunchProcess( if (!noShellExecute && readStandardHandles) throw new InvalidOperationException("Requesting output/error reading requires noShellExecute to be true!"); - logger.LogDebug( - noShellExecute - ? "Launching process in {workingDirectory}: {exe} {arguments}" - : "Shell launching process in {workingDirectory}: {exe} {arguments}", + if (noShellExecute) + logger.LogDebug( + "Launching process in {workingDirectory}: {exe} {arguments}", workingDirectory, fileName, arguments); + else + logger.LogDebug( + "Shell launching process in {workingDirectory}: {exe} {arguments}", + workingDirectory, + fileName, + arguments); + var handle = new global::System.Diagnostics.Process(); try { From 6ce9695533e23c857329950098c540c27ca796cd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 11:22:01 -0500 Subject: [PATCH 436/717] Redo Process output reading to better workaround https://github.com/dotnet/runtime/issues/28583 Also test harder --- src/Tgstation.Server.Host/System/IProcess.cs | 5 +- src/Tgstation.Server.Host/System/Process.cs | 27 +---- .../System/ProcessExecutor.cs | 100 ++++++++++-------- .../System/TestPosixSignalHandler.cs | 3 +- .../Live/Instance/WatchdogTest.cs | 1 - .../Live/TestLiveServer.cs | 1 - .../TestSystemInteraction.cs | 44 ++++---- tests/Tgstation.Server.Tests/TestVersions.cs | 3 +- 8 files changed, 84 insertions(+), 100 deletions(-) diff --git a/src/Tgstation.Server.Host/System/IProcess.cs b/src/Tgstation.Server.Host/System/IProcess.cs index 8df102b2b2a..dc9a1d5eac5 100644 --- a/src/Tgstation.Server.Host/System/IProcess.cs +++ b/src/Tgstation.Server.Host/System/IProcess.cs @@ -23,13 +23,12 @@ interface IProcess : IProcessBase, IAsyncDisposable /// Get the stderr and stdout output of the . /// /// The for the operation. - /// A resulting in the stderr and stdout output of the . + /// A resulting in the stderr and stdout output of the . /// /// To guarantee that all data is received from the when redirecting streams to a file /// the result of this function must be ed before is called. - /// May call internally if the process has exited. /// - ValueTask GetCombinedOutput(CancellationToken cancellationToken); + Task GetCombinedOutput(CancellationToken cancellationToken); /// /// Asycnhronously terminates the process. diff --git a/src/Tgstation.Server.Host/System/Process.cs b/src/Tgstation.Server.Host/System/Process.cs index 210a86db8c6..266e2207085 100644 --- a/src/Tgstation.Server.Host/System/Process.cs +++ b/src/Tgstation.Server.Host/System/Process.cs @@ -7,7 +7,6 @@ using Microsoft.Win32.SafeHandles; using Tgstation.Server.Host.IO; -using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.System { @@ -28,11 +27,6 @@ sealed class Process : IProcess /// readonly IProcessFeatures processFeatures; - /// - /// The for the . - /// - readonly IAsyncDelayer asyncDelayer; - /// /// The for the . /// @@ -68,7 +62,6 @@ sealed class Process : IProcess /// Initializes a new instance of the class. /// /// The value of . - /// The value of . /// The value of . /// The override value of . /// The value of . @@ -76,7 +69,6 @@ sealed class Process : IProcess /// If was NOT just created. public Process( IProcessFeatures processFeatures, - IAsyncDelayer asyncDelayer, global::System.Diagnostics.Process handle, CancellationTokenSource readerCts, Task readTask, @@ -92,7 +84,6 @@ public Process( cancellationTokenSource = readerCts ?? new CancellationTokenSource(); this.processFeatures = processFeatures ?? throw new ArgumentNullException(nameof(processFeatures)); - this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.readTask = readTask; @@ -144,26 +135,12 @@ public async ValueTask DisposeAsync() } /// - public async ValueTask GetCombinedOutput(CancellationToken cancellationToken) + public Task GetCombinedOutput(CancellationToken cancellationToken) { - CheckDisposed(); if (readTask == null) throw new InvalidOperationException("Output/Error stream reading was not enabled!"); - // workaround for https://github.com/dotnet/runtime/issues/28583 (?) - if (handle.HasExited) - { - handle.WaitForExit(); - await Task.WhenAny(readTask, asyncDelayer.Delay(TimeSpan.FromSeconds(30), cancellationToken)); - - if (!readTask.IsCompleted) - { - logger.LogWarning("Detected process output read hang on PID {pid}! Closing handle as a workaround...", Id); - cancellationTokenSource.Cancel(); - } - } - - return await readTask.WaitAsync(cancellationToken); + return readTask.WaitAsync(cancellationToken); } /// diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index acea2604ffa..4f54ce62b3b 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.Logging; using Tgstation.Server.Host.IO; -using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.System { @@ -24,11 +23,6 @@ sealed class ProcessExecutor : IProcessExecutor /// readonly IProcessFeatures processFeatures; - /// - /// The for the . - /// - readonly IAsyncDelayer asyncDelayer; - /// /// The for the . /// @@ -65,19 +59,16 @@ public static void WithProcessLaunchExclusivity(Action action) /// Initializes a new instance of the class. /// /// The value of . - /// The value of . /// The value of . /// The value of . /// The value of . public ProcessExecutor( IProcessFeatures processFeatures, - IAsyncDelayer asyncDelayer, IIOManager ioManager, ILogger logger, ILoggerFactory loggerFactory) { this.processFeatures = processFeatures ?? throw new ArgumentNullException(nameof(processFeatures)); - this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); @@ -122,9 +113,6 @@ public IProcess LaunchProcess( ArgumentNullException.ThrowIfNull(workingDirectory); ArgumentNullException.ThrowIfNull(arguments); - if (!noShellExecute && readStandardHandles) - throw new InvalidOperationException("Requesting output/error reading requires noShellExecute to be true!"); - if (noShellExecute) logger.LogDebug( "Launching process in {workingDirectory}: {exe} {arguments}", @@ -151,10 +139,10 @@ public IProcess LaunchProcess( CancellationTokenSource disposeCts = null; try { - TaskCompletionSource processStartTcs = null; + TaskCompletionSource processStartTcs = null; if (readStandardHandles) { - processStartTcs = new TaskCompletionSource(); + processStartTcs = new TaskCompletionSource(); handle.StartInfo.RedirectStandardOutput = true; handle.StartInfo.RedirectStandardError = true; @@ -162,6 +150,7 @@ public IProcess LaunchProcess( readTask = ConsumeReaders(handle, processStartTcs.Task, fileRedirect, disposeCts.Token); } + int pid; try { ExclusiveProcessLaunchLock.EnterReadLock(); @@ -174,7 +163,8 @@ public IProcess LaunchProcess( ExclusiveProcessLaunchLock.ExitReadLock(); } - processStartTcs?.SetResult(); + pid = handle.Id; + processStartTcs?.SetResult(pid); } catch (Exception ex) { @@ -184,7 +174,6 @@ public IProcess LaunchProcess( var process = new Process( processFeatures, - asyncDelayer, handle, disposeCts, readTask, @@ -231,43 +220,53 @@ public IProcess GetProcessByName(string name) /// Consume the stdout/stderr streams into a . /// /// The . - /// The that completes when starts. + /// The resulting in the of the started process. /// The optional path to redirect the streams to. /// The that triggers when the is disposed. /// A resulting in the program's output/error text if is , otherwise. - async Task ConsumeReaders(global::System.Diagnostics.Process handle, Task startTask, string fileRedirect, CancellationToken disposeToken) + async Task ConsumeReaders(global::System.Diagnostics.Process handle, Task startupAndPid, string fileRedirect, CancellationToken disposeToken) { - await startTask; - - var pid = handle.Id; + var pid = await startupAndPid; logger.LogTrace("Starting read for PID {pid}...", pid); - // once we obtain these handles we're responsible for them - using var stdOutHandle = handle.StandardOutput; - using var stdErrHandle = handle.StandardError; - Task outputReadTask = null, errorReadTask = null; + var stdOutHandle = handle.StandardOutput; + var stdErrHandle = handle.StandardError; bool outputOpen = true, errorOpen = true; - async Task GetNextLine() + var outputReadTask = stdOutHandle.ReadLineAsync(disposeToken).AsTask(); + var errorReadTask = stdErrHandle.ReadLineAsync(disposeToken).AsTask(); + + async ValueTask GetNextLine() { - if (outputOpen && outputReadTask == null) - outputReadTask = stdOutHandle.ReadLineAsync(disposeToken).AsTask(); + var nextLineTask = outputOpen + ? errorOpen + ? await Task.WhenAny(outputReadTask, errorReadTask) + : outputReadTask + : errorReadTask; - if (errorOpen && errorReadTask == null) - errorReadTask = stdErrHandle.ReadLineAsync(disposeToken).AsTask(); + var line = await nextLineTask; - var completedTask = await Task.WhenAny(outputReadTask ?? errorReadTask, errorReadTask ?? outputReadTask); - var line = await completedTask.WaitAsync(disposeToken); - if (completedTask == outputReadTask) + // Important to retrigger the reading block asap after pushing + if (nextLineTask == outputReadTask) { - outputReadTask = null; if (line == null) + { outputOpen = false; + outputReadTask = null; + } + else + outputReadTask = stdOutHandle.ReadLineAsync(disposeToken).AsTask(); } else { - errorReadTask = null; + global::System.Diagnostics.Debug.Assert(nextLineTask == errorReadTask, "How is this incorrect?"); + if (line == null) + { errorOpen = false; + errorReadTask = null; + } + else + errorReadTask = stdErrHandle.ReadLineAsync(disposeToken).AsTask(); } if (line == null && (errorOpen || outputOpen)) @@ -279,20 +278,32 @@ async Task GetNextLine() await using var fileStream = fileRedirect != null ? ioManager.CreateAsyncSequentialWriteStream(fileRedirect) : null; await using var writer = fileStream != null ? new StreamWriter(fileStream) : null; - string text; var stringBuilder = fileStream == null ? new StringBuilder() : null; - try + ulong fileFlushToken = 0; + async ValueTask QueueWrite(ValueTask previous, string text) { - while ((text = await GetNextLine()) != null) + if (fileStream != null) { - if (fileStream != null) - { - await writer.WriteLineAsync(text.AsMemory(), disposeToken); + var startFlushToken = Interlocked.Increment(ref fileFlushToken); + await previous; + await writer.WriteLineAsync(text.AsMemory(), disposeToken); + + // only flush if there isn't anything rapidly coming in + if (fileFlushToken == startFlushToken) await writer.FlushAsync(disposeToken); - } - else - stringBuilder.AppendLine(text); } + else + stringBuilder.AppendLine(text); + } + + ValueTask writeQueue = ValueTask.CompletedTask; + try + { + string text; + while ((text = await GetNextLine()) != null) + writeQueue = QueueWrite(writeQueue, text); + + await writeQueue; logger.LogTrace("Finished read for PID {pid}", pid); } @@ -318,7 +329,6 @@ Process CreateFromExistingHandle(global::System.Diagnostics.Process handle) var pid = handle.Id; return new Process( processFeatures, - asyncDelayer, handle, null, null, diff --git a/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs b/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs index 407145730cc..6728fe09b62 100644 --- a/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs +++ b/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Reflection; using System.Threading; @@ -60,7 +60,6 @@ public async Task TestSignalListening() new Lazy(() => processExecutor), new DefaultIOManager(), loggerFactory.CreateLogger()), - new AsyncDelayer(), Mock.Of(), loggerFactory.CreateLogger(), loggerFactory); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 8fcccf05892..6071dade632 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -739,7 +739,6 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? new WindowsProcessFeatures(Mock.Of>()) : new PosixProcessFeatures(new Lazy(() => executor), Mock.Of(), Mock.Of>()), - Mock.Of(), Mock.Of(), Mock.Of>(), LoggerFactory.Create(x => { })); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 5707027a920..bc0a8c5e5af 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1081,7 +1081,6 @@ await ioManager.CopyDirectory( new PlatformIdentifier().IsWindows ? new WindowsProcessFeatures(loggerFactory.CreateLogger()) : new PosixProcessFeatures(new Lazy(() => processExecutor), ioManager, loggerFactory.CreateLogger()), - new AsyncDelayer(), ioManager, loggerFactory.CreateLogger(), loggerFactory); diff --git a/tests/Tgstation.Server.Tests/TestSystemInteraction.cs b/tests/Tgstation.Server.Tests/TestSystemInteraction.cs index 45a017a9680..98b7c82f441 100644 --- a/tests/Tgstation.Server.Tests/TestSystemInteraction.cs +++ b/tests/Tgstation.Server.Tests/TestSystemInteraction.cs @@ -24,7 +24,6 @@ public async Task TestScriptExecutionWithStdRead() var platformIdentifier = new PlatformIdentifier(); var processExecutor = new ProcessExecutor( Mock.Of(), - Mock.Of(), new DefaultIOManager(), Mock.Of>(), loggerFactory); @@ -53,36 +52,39 @@ public async Task TestScriptExecutionWithFileOutput() var platformIdentifier = new PlatformIdentifier(); var processExecutor = new ProcessExecutor( Mock.Of(), - Mock.Of(), new DefaultIOManager(), loggerFactory.CreateLogger(), loggerFactory); - var tempFile = Path.GetTempFileName(); - File.Delete(tempFile); - try + // run on a loop to spot the hang + for (var i = 0; i < 1000; ++i) { - await using (var process = processExecutor.LaunchProcess("test." + platformIdentifier.ScriptFileExtension, ".", string.Empty, tempFile, true, true)) + var tempFile = Path.GetTempFileName(); + File.Delete(tempFile); + try { - using var cts = new CancellationTokenSource(); - cts.CancelAfter(3000); - var exitCode = await process.Lifetime.WaitAsync(cts.Token); + await using (var process = processExecutor.LaunchProcess("test." + platformIdentifier.ScriptFileExtension, ".", string.Empty, tempFile, true, true)) + { + using var cts = new CancellationTokenSource(); + cts.CancelAfter(3000); + var exitCode = await process.Lifetime.WaitAsync(cts.Token); - await process.GetCombinedOutput(cts.Token); + await process.GetCombinedOutput(cts.Token); - Assert.AreEqual(0, exitCode); - } + Assert.AreEqual(0, exitCode); + } - Assert.IsTrue(File.Exists(tempFile), $"Could not find temp file: {tempFile}"); - var result = File.ReadAllText(tempFile).Trim(); + Assert.IsTrue(File.Exists(tempFile), $"Could not find temp file: {tempFile}"); + var result = File.ReadAllText(tempFile).Trim(); - // no guarantees about order - Assert.IsTrue(result.Contains("Hello World!"), $"Result: {result}"); - Assert.IsTrue(result.Contains("Hello Error!"), $"Result: {result}"); - } - finally - { - File.Delete(tempFile); + // no guarantees about order + Assert.IsTrue(result.Contains("Hello World!"), $"Result: {result}"); + Assert.IsTrue(result.Contains("Hello Error!"), $"Result: {result}"); + } + finally + { + File.Delete(tempFile); + } } } } diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 3dd20d8e7b0..1ef0da6fd79 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.IO.Compression; using System.Globalization; @@ -208,7 +208,6 @@ await CachingFileDownloader.InitializeByondVersion( new Lazy(() => null), Mock.Of(), loggerFactory.CreateLogger()), - Mock.Of(), Mock.Of(), loggerFactory.CreateLogger(), loggerFactory); From c06af410415a3d7afeef01504e21adc7dc172532 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 11:22:08 -0500 Subject: [PATCH 437/717] Cleanup some messages --- .../System/TestPosixSignalHandler.cs | 4 ++-- tests/Tgstation.Server.Tests/TestVersions.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs b/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs index 6728fe09b62..083657a0753 100644 --- a/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs +++ b/tests/Tgstation.Server.Host.Tests/System/TestPosixSignalHandler.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Reflection; using System.Threading; @@ -54,7 +54,7 @@ public async Task TestSignalListening() builder.SetMinimumLevel(LogLevel.Trace); }); - IProcessExecutor processExecutor = null; + ProcessExecutor processExecutor = null; processExecutor = new ProcessExecutor( new PosixProcessFeatures( new Lazy(() => processExecutor), diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 1ef0da6fd79..34dad9e0066 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.IO.Compression; using System.Globalization; @@ -463,8 +463,8 @@ static async Task TestMapThreadsVersion( EngineVersion engineVersion, Stream byondBytes, ByondInstallerBase byondInstaller, - IIOManager ioManager, - IProcessExecutor processExecutor, + DefaultIOManager ioManager, + ProcessExecutor processExecutor, string tempPath) { using (byondBytes) From 37c54c1fbdb28b2b1139231d5f3bf4aaece55a63 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 11:26:31 -0500 Subject: [PATCH 438/717] Increase some timeouts that were too low --- tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs | 2 +- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs index d0d074e6e88..a0cf0d9af19 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs @@ -139,7 +139,7 @@ public async Task RunPostRepoClone(Task byondTask, CancellationToken cancellatio var updatedDD = await dreamDaemonClient.Update(new DreamDaemonRequest { - StartupTimeout = 15, + StartupTimeout = 30, Port = ddPort }, cancellationToken); Assert.AreEqual(15U, updatedDD.StartupTimeout); diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 6071dade632..acb1a095e03 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -133,7 +133,7 @@ await Task.WhenAll( // Increase startup timeout, disable heartbeats, enable map threads because we've tested without for years instanceClient.DreamDaemon.Update(new DreamDaemonRequest { - StartupTimeout = 15, + StartupTimeout = 30, HealthCheckSeconds = 0, Port = ddPort, MapThreads = 2, From 0e209b933fc9a078902293a47edf530fc2e092bf Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 11:34:04 -0500 Subject: [PATCH 439/717] Essentially remove live tests token expiry --- tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs index 6fce2c452c9..61a7a36176c 100644 --- a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs +++ b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs @@ -153,6 +153,7 @@ public LiveTestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth $"Session:LowPriorityDeploymentProcesses={LowPriorityDeployments}", $"General:SkipAddingByondFirewallException={!TestingUtils.RunningInGitHubActions}", $"General:OpenDreamGitUrl={OpenDreamUrl}", + $"Security:TokenExpiryMinutes=120", // timeouts are useless for us }; swarmArgs = new List(); From f870aa0b178baf03a08bd1edc3d5d6dafa29f562 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 11:37:39 -0500 Subject: [PATCH 440/717] Remove some whitespace --- tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 611ee9ed6fc..a50d4a65043 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -221,7 +221,6 @@ await DownloadEngineVersion(compatVersion, fileDownloader, openDreamUrl, cancell await chatRequest; await Task.Yield(); - await Task.WhenAll( jrt.WaitForJob(installJob2.InstallJob, EngineTest.EngineInstallationTimeout(compatVersion) + 30, false, null, cancellationToken), jrt.WaitForJob(cloneRequest.Result.ActiveJob, 60, false, null, cancellationToken), From a3689ac4a9d7aed7c09dc675a2cf0efa25b04443 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 13:14:11 -0500 Subject: [PATCH 441/717] Remove bad reference --- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 6a2262dfa42..a47c87fbd27 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -129,7 +129,6 @@ - From 670fe5084760236f2f4e96c806e6cb565b46a1fd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 13:16:57 -0500 Subject: [PATCH 442/717] Fix assert --- tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs index a0cf0d9af19..8cc7d0b6fb7 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/DeploymentTest.cs @@ -142,7 +142,7 @@ public async Task RunPostRepoClone(Task byondTask, CancellationToken cancellatio StartupTimeout = 30, Port = ddPort }, cancellationToken); - Assert.AreEqual(15U, updatedDD.StartupTimeout); + Assert.AreEqual(30U, updatedDD.StartupTimeout); Assert.AreEqual(ddPort, updatedDD.Port); async Task CompileAfterByondInstall() From 2d5def6fdb4fc33b8df430a17c8ad3ead559369c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 15:06:42 -0500 Subject: [PATCH 443/717] Correct firewall rule name for OpenDream --- .../Components/Engine/WindowsOpenDreamInstaller.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index 4f42884c7f3..40628846045 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -102,7 +102,7 @@ async ValueTask AddServerFirewallException(EngineVersion version, string path, C // I really wish we could add the instance name here but // 1. It'd make IByondInstaller need to be transient per-instance and WindowsByondInstaller relys on being a singleton for its DX installer call // 2. The instance could be renamed, so it'd have to be an unfriendly ID anyway. - var ruleName = $"TGS DreamDaemon {version}"; + var ruleName = $"TGS OpenDream {version}"; exitCode = await WindowsFirewallHelper.AddFirewallException( ProcessExecutor, From f12ecfd73832bd9437562e9b33542b5ef8aa2792 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 15:45:17 -0500 Subject: [PATCH 444/717] Fix connecting to an existing SQLite database --- src/Tgstation.Server.Host/Setup/SetupWizard.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index b9671572b29..79f30c22b98 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -600,6 +600,8 @@ void CreateTestConnection(string connectionString) => }; CreateTestConnection(csb.ConnectionString); + + csb.Mode = SqliteOpenMode.ReadWriteCreate; databaseConfiguration.ConnectionString = csb.ConnectionString; } From e28db583daa86a96a9f1aac1b106b89483cb6031 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 16:14:11 -0500 Subject: [PATCH 445/717] Remove superfluous assignments --- src/Tgstation.Server.Host/System/ProcessExecutor.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index 4f54ce62b3b..52b2c8d2222 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.IO; using System.Text; using System.Threading; @@ -247,24 +248,16 @@ async ValueTask GetNextLine() // Important to retrigger the reading block asap after pushing if (nextLineTask == outputReadTask) - { if (line == null) - { outputOpen = false; - outputReadTask = null; - } else outputReadTask = stdOutHandle.ReadLineAsync(disposeToken).AsTask(); - } else { - global::System.Diagnostics.Debug.Assert(nextLineTask == errorReadTask, "How is this incorrect?"); + Debug.Assert(nextLineTask == errorReadTask, "How is this incorrect?"); if (line == null) - { errorOpen = false; - errorReadTask = null; - } else errorReadTask = stdErrHandle.ReadLineAsync(disposeToken).AsTask(); } From fba969b2f1ab26faf06c24ccfb8345236d585539 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 16:14:39 -0500 Subject: [PATCH 446/717] Setup basic WSL debug environment --- .../Properties/launchSettings.json | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Properties/launchSettings.json b/src/Tgstation.Server.Host/Properties/launchSettings.json index 52ba379ea36..b93f29050d8 100644 --- a/src/Tgstation.Server.Host/Properties/launchSettings.json +++ b/src/Tgstation.Server.Host/Properties/launchSettings.json @@ -7,9 +7,15 @@ "ASPNETCORE_ENVIRONMENT": "Development" } }, - "Docker": { - "commandName": "Docker", - "publishAllPorts": true + "WSL": { + "commandName": "WSL2", + "distributionName": "Ubuntu", + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development", + "ASPNETCORE_ENVIRONMENT": "Development", + "Database__ConnectionString": "Data Source=192.168.2.16,1433;Initial Catalog=TGS_Linux;User Id=tgs_debug;Password=asdf;Encrypt=False;Application Name=tgstation-server", + "General__ValidInstancePaths__0": "/home/dominion/tgs_debug_pen" + } } } -} \ No newline at end of file +} From 50c2fd20ad6458461a29850a58c604d63fbbb0ec Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 16:16:15 -0500 Subject: [PATCH 447/717] Increase OpenDream test installation timeout again --- tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs index 83e7f322c9b..57c4255130b 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs @@ -140,7 +140,7 @@ public static int EngineInstallationTimeout(EngineVersion testVersion) case EngineType.Byond: return 30; case EngineType.OpenDream: - return 300; + return 500; default: throw new InvalidOperationException($"Unknown engine type: {testVersion.Engine.Value}"); } From 35e8c33cd2918f0ad8135b5c5eb3e68685d9314e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 16:31:15 -0500 Subject: [PATCH 448/717] Add more assertions because something is fucky --- src/Tgstation.Server.Host/System/ProcessExecutor.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index 52b2c8d2222..d6782d4512c 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -238,6 +238,10 @@ async Task ConsumeReaders(global::System.Diagnostics.Process handle, Tas async ValueTask GetNextLine() { + Debug.Assert(outputOpen || errorOpen, "We shouldn't be here if neither stream is open"); + Debug.Assert(outputOpen || outputReadTask.IsCompleted, "Output open flag mismatch"); + Debug.Assert(errorOpen || errorReadTask.IsCompleted, "Error open flag mismatch"); + var nextLineTask = outputOpen ? errorOpen ? await Task.WhenAny(outputReadTask, errorReadTask) From 0810db2c8eb2ab09a2e12511bd9d87827e4ab26c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 16:49:54 -0500 Subject: [PATCH 449/717] Clean up some Stylecop 'L's --- .../Components/Engine/OpenDreamInstaller.cs | 4 +++- .../Engine/WindowsOpenDreamInstaller.cs | 21 +++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index bbd09ed1c1d..6b356ba5391 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -276,7 +276,9 @@ await Task.WhenAll( cancellationToken))); } - await ValueTaskExtensions.WhenAll(MoveDirs(), MoveFiles()); + var dirsMoveTask = MoveDirs(); + var outputFilesMoveTask = MoveFiles(); + await ValueTaskExtensions.WhenAll(dirsMoveTask, outputFilesMoveTask); await IOManager.DeleteDirectory(sourcePath, cancellationToken); } diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index 40628846045..c97ca10418e 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -56,15 +56,18 @@ public WindowsOpenDreamInstaller( /// public override ValueTask Install(EngineVersion version, string installPath, CancellationToken cancellationToken) - => ValueTaskExtensions.WhenAll( - base.Install( - version, - installPath, - cancellationToken), - AddServerFirewallException( - version, - installPath, - cancellationToken)); + { + var installTask = base.Install( + version, + installPath, + cancellationToken); + var firewallTask = AddServerFirewallException( + version, + installPath, + cancellationToken); + + return ValueTaskExtensions.WhenAll(installTask, firewallTask); + } /// protected override async ValueTask HandleExtremelyLongPathOperation(Func shortenedPathOperation, string originalPath, CancellationToken cancellationToken) From 441985ff83ea22fdf13c683700ae0d835130046e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 16:50:11 -0500 Subject: [PATCH 450/717] Further readdress process output handling --- .../System/ProcessExecutor.cs | 65 +++++++++++++------ 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index d6782d4512c..29ea83129aa 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -3,6 +3,7 @@ using System.IO; using System.Text; using System.Threading; +using System.Threading.Channels; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -223,9 +224,9 @@ public IProcess GetProcessByName(string name) /// The . /// The resulting in the of the started process. /// The optional path to redirect the streams to. - /// The that triggers when the is disposed. + /// The for the operation. /// A resulting in the program's output/error text if is , otherwise. - async Task ConsumeReaders(global::System.Diagnostics.Process handle, Task startupAndPid, string fileRedirect, CancellationToken disposeToken) + async Task ConsumeReaders(global::System.Diagnostics.Process handle, Task startupAndPid, string fileRedirect, CancellationToken cancellationToken) { var pid = await startupAndPid; logger.LogTrace("Starting read for PID {pid}...", pid); @@ -233,8 +234,11 @@ async Task ConsumeReaders(global::System.Diagnostics.Process handle, Tas var stdOutHandle = handle.StandardOutput; var stdErrHandle = handle.StandardError; bool outputOpen = true, errorOpen = true; - var outputReadTask = stdOutHandle.ReadLineAsync(disposeToken).AsTask(); - var errorReadTask = stdErrHandle.ReadLineAsync(disposeToken).AsTask(); + + Task ReadHandle(StreamReader handle) => handle.ReadLineAsync(cancellationToken).AsTask(); + + var outputReadTask = ReadHandle(stdOutHandle); + var errorReadTask = ReadHandle(stdErrHandle); async ValueTask GetNextLine() { @@ -255,7 +259,7 @@ async ValueTask GetNextLine() if (line == null) outputOpen = false; else - outputReadTask = stdOutHandle.ReadLineAsync(disposeToken).AsTask(); + outputReadTask = ReadHandle(stdOutHandle); else { Debug.Assert(nextLineTask == errorReadTask, "How is this incorrect?"); @@ -263,7 +267,7 @@ async ValueTask GetNextLine() if (line == null) errorOpen = false; else - errorReadTask = stdErrHandle.ReadLineAsync(disposeToken).AsTask(); + errorReadTask = ReadHandle(stdErrHandle); } if (line == null && (errorOpen || outputOpen)) @@ -276,31 +280,52 @@ async ValueTask GetNextLine() await using var writer = fileStream != null ? new StreamWriter(fileStream) : null; var stringBuilder = fileStream == null ? new StringBuilder() : null; - ulong fileFlushToken = 0; - async ValueTask QueueWrite(ValueTask previous, string text) + + var dataChannel = Channel.CreateUnbounded( + new UnboundedChannelOptions + { + AllowSynchronousContinuations = false, + SingleReader = true, + SingleWriter = true, + }); + + async ValueTask OutputWriter() { + var enumerable = dataChannel.Reader.ReadAllAsync(cancellationToken); if (fileStream != null) { - var startFlushToken = Interlocked.Increment(ref fileFlushToken); - await previous; - await writer.WriteLineAsync(text.AsMemory(), disposeToken); + var enumerator = enumerable.GetAsyncEnumerator(cancellationToken); + var nextEnumeration = enumerator.MoveNextAsync(); + while (await nextEnumeration) + { + var text = enumerator.Current; + nextEnumeration = enumerator.MoveNextAsync(); + await writer.WriteLineAsync(text.AsMemory(), cancellationToken); - // only flush if there isn't anything rapidly coming in - if (fileFlushToken == startFlushToken) - await writer.FlushAsync(disposeToken); + if (!nextEnumeration.IsCompleted) + await writer.FlushAsync(cancellationToken); + } } else - stringBuilder.AppendLine(text); + await foreach (var text in enumerable) + stringBuilder.AppendLine(text); } - ValueTask writeQueue = ValueTask.CompletedTask; try { - string text; - while ((text = await GetNextLine()) != null) - writeQueue = QueueWrite(writeQueue, text); + var outputWriterTask = OutputWriter(); + try + { + string text; + while ((text = await GetNextLine()) != null) + await dataChannel.Writer.WriteAsync(text, cancellationToken); - await writeQueue; + dataChannel.Writer.Complete(); + } + finally + { + await outputWriterTask; + } logger.LogTrace("Finished read for PID {pid}", pid); } From 40c5ba97b4c280793e371db46a2f5f8a1a62e39a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 16:51:44 -0500 Subject: [PATCH 451/717] Update to `actions/checkout@v4` --- .github/workflows/ci-pipeline.yml | 70 ++++++++++++++--------------- .github/workflows/code-scanning.yml | 2 +- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 4f5a0f95d26..1efe65423b9 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -137,11 +137,11 @@ jobs: exit 0 - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -183,11 +183,11 @@ jobs: dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -223,11 +223,11 @@ jobs: dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -287,11 +287,11 @@ jobs: if: (!(cancelled() || failure()) && needs.start-ci-run-gate.result == 'success') steps: - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -325,11 +325,11 @@ jobs: dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -376,11 +376,11 @@ jobs: dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -491,11 +491,11 @@ jobs: echo "TGS_TEST_DATABASE_TYPE=SqlServer" >> $GITHUB_ENV - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -696,11 +696,11 @@ jobs: run: echo "General__UseBasicWatchdog=true" >> $GITHUB_ENV - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -775,11 +775,11 @@ jobs: run: npm i -g ibm-openapi-validator@0.51.3 - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -800,11 +800,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -1088,11 +1088,11 @@ jobs: echo "New dotnet path should be $DOTNET_PATH" - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -1171,11 +1171,11 @@ jobs: dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -1303,11 +1303,11 @@ jobs: echo "pr_template_sha=$(cat commits.json | jq '.[0].sha')" >> $GITHUB_OUTPUT - name: Checkout (Branch) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name == 'push' || github.event_name == 'schedule' - name: Checkout (PR Merge) - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: github.event_name != 'push' && github.event_name != 'schedule' with: ref: "refs/pull/${{ github.event.number }}/merge" @@ -1352,7 +1352,7 @@ jobs: dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Restore run: dotnet restore @@ -1416,7 +1416,7 @@ jobs: dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Restore run: dotnet restore @@ -1479,7 +1479,7 @@ jobs: dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Restore run: dotnet restore @@ -1530,7 +1530,7 @@ jobs: dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Restore run: dotnet restore @@ -1554,7 +1554,7 @@ jobs: dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Restore run: dotnet restore @@ -1766,7 +1766,7 @@ jobs: dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Restore run: dotnet restore @@ -1805,7 +1805,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Parse TGS version run: | @@ -1829,7 +1829,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Parse TGS version run: | @@ -1862,7 +1862,7 @@ jobs: run: winget install wingetcreate --version 1.2.8.0 --disable-interactivity --accept-source-agreements # Pinned due to breaking every other version - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Build ReleaseNotes run: dotnet build -c Release -p:TGS_HOST_NO_WEBPANEL=true tools/Tgstation.Server.ReleaseNotes diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml index a0e8069a33e..a7baad0e0eb 100644 --- a/.github/workflows/code-scanning.yml +++ b/.github/workflows/code-scanning.yml @@ -37,7 +37,7 @@ jobs: dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v2 From b86b4765eecc8a0006ece1c5b2a9636cf6d7491d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 17:06:23 -0500 Subject: [PATCH 452/717] Another `ProcessExecutor.ConsumeReaders` rewrite --- .../System/ProcessExecutor.cs | 79 +++++++------------ 1 file changed, 28 insertions(+), 51 deletions(-) diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index 29ea83129aa..0deae3507a5 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.IO; using System.Text; using System.Threading; @@ -8,6 +7,7 @@ using Microsoft.Extensions.Logging; +using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.IO; namespace Tgstation.Server.Host.System @@ -233,50 +233,9 @@ async Task ConsumeReaders(global::System.Diagnostics.Process handle, Tas var stdOutHandle = handle.StandardOutput; var stdErrHandle = handle.StandardError; - bool outputOpen = true, errorOpen = true; - Task ReadHandle(StreamReader handle) => handle.ReadLineAsync(cancellationToken).AsTask(); - - var outputReadTask = ReadHandle(stdOutHandle); - var errorReadTask = ReadHandle(stdErrHandle); - - async ValueTask GetNextLine() - { - Debug.Assert(outputOpen || errorOpen, "We shouldn't be here if neither stream is open"); - Debug.Assert(outputOpen || outputReadTask.IsCompleted, "Output open flag mismatch"); - Debug.Assert(errorOpen || errorReadTask.IsCompleted, "Error open flag mismatch"); - - var nextLineTask = outputOpen - ? errorOpen - ? await Task.WhenAny(outputReadTask, errorReadTask) - : outputReadTask - : errorReadTask; - - var line = await nextLineTask; - - // Important to retrigger the reading block asap after pushing - if (nextLineTask == outputReadTask) - if (line == null) - outputOpen = false; - else - outputReadTask = ReadHandle(stdOutHandle); - else - { - Debug.Assert(nextLineTask == errorReadTask, "How is this incorrect?"); - - if (line == null) - errorOpen = false; - else - errorReadTask = ReadHandle(stdErrHandle); - } - - if (line == null && (errorOpen || outputOpen)) - return await GetNextLine(); - - return line; - } - - await using var fileStream = fileRedirect != null ? ioManager.CreateAsyncSequentialWriteStream(fileRedirect) : null; + bool writingToFile; + await using var fileStream = (writingToFile = fileRedirect != null) ? ioManager.CreateAsyncSequentialWriteStream(fileRedirect) : null; await using var writer = fileStream != null ? new StreamWriter(fileStream) : null; var stringBuilder = fileStream == null ? new StringBuilder() : null; @@ -284,15 +243,34 @@ async ValueTask GetNextLine() var dataChannel = Channel.CreateUnbounded( new UnboundedChannelOptions { - AllowSynchronousContinuations = false, + AllowSynchronousContinuations = !writingToFile, SingleReader = true, - SingleWriter = true, + SingleWriter = false, }); + var handlesOpen = 2; + async ValueTask DrainHandle(StreamReader reader) + { + while (true) + { + var line = await reader.ReadLineAsync(cancellationToken); + if (line == null) + { + var handlesRemaining = Interlocked.Decrement(ref handlesOpen); + if (handlesRemaining == 0) + dataChannel.Writer.Complete(); + + break; + } + + await dataChannel.Writer.WriteAsync(line, cancellationToken); + } + } + async ValueTask OutputWriter() { var enumerable = dataChannel.Reader.ReadAllAsync(cancellationToken); - if (fileStream != null) + if (writingToFile) { var enumerator = enumerable.GetAsyncEnumerator(cancellationToken); var nextEnumeration = enumerator.MoveNextAsync(); @@ -316,11 +294,10 @@ async ValueTask OutputWriter() var outputWriterTask = OutputWriter(); try { - string text; - while ((text = await GetNextLine()) != null) - await dataChannel.Writer.WriteAsync(text, cancellationToken); + var outputReadTask = DrainHandle(stdOutHandle); + var errorReadTask = DrainHandle(stdErrHandle); - dataChannel.Writer.Complete(); + await ValueTaskExtensions.WhenAll(outputReadTask, errorReadTask); } finally { From 1c14cf60e495d70682d8b7ee88de2b52f889fbf5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 17:06:28 -0500 Subject: [PATCH 453/717] Simplify a null check --- src/Tgstation.Server.Host/Database/DatabaseContext.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Database/DatabaseContext.cs b/src/Tgstation.Server.Host/Database/DatabaseContext.cs index cca6313b532..3dd14560f65 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseContext.cs @@ -245,11 +245,8 @@ public static Action GetConfigur 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!"); - + BindingFlags.Public | BindingFlags.Static) + ?? throw new InvalidOperationException($"Context type {typeof(TDatabaseContext).FullName} missing static {ConfigureMethodName} function!"); return (optionsBuilder, config) => configureFunction.Invoke(null, new object[] { optionsBuilder, config }); } From 343b8c69ba8de71d003f481c3c28e34b4f78027e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 22:33:42 -0500 Subject: [PATCH 454/717] Sync topics sent in tests with `SessionController` --- .../Components/Session/SessionController.cs | 18 +++---- .../Live/Instance/WatchdogTest.cs | 49 +++++++++++-------- .../Live/TestLiveServer.cs | 26 +++++----- 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index cefdcff76db..2e57410eab2 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -108,6 +108,11 @@ async Task Wrap() /// public ReattachInformation ReattachInformation { get; } + /// + /// The used to prevent concurrent calls into /world/Topic(). + /// + public FifoSemaphore TopicSendSemaphore { get; } + /// /// The for the . /// @@ -148,11 +153,6 @@ async Task Wrap() /// readonly TaskCompletionSource initialBridgeRequestTcs; - /// - /// The used to prevent concurrent calls into /world/Topic(). - /// - readonly FifoSemaphore topicSendSemaphore; - /// /// The metadata. /// @@ -285,7 +285,7 @@ public SessionController( initialBridgeRequestTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); reattachTopicCts = new CancellationTokenSource(); - topicSendSemaphore = new FifoSemaphore(); + TopicSendSemaphore = new FifoSemaphore(); synchronizationLock = new object(); if (apiValidationSession || DMApiAvailable) @@ -338,7 +338,7 @@ public async ValueTask DisposeAsync() Logger.LogTrace("Disposing..."); reattachTopicCts.Cancel(); - var semaphoreLockTask = topicSendSemaphore.Lock(CancellationToken.None); // DCT: None available + var semaphoreLockTask = TopicSendSemaphore.Lock(CancellationToken.None); // DCT: None available if (!released) { @@ -363,7 +363,7 @@ public async ValueTask DisposeAsync() await Lifetime; // finish the async callback (await semaphoreLockTask).Dispose(); - topicSendSemaphore.Dispose(); + TopicSendSemaphore.Dispose(); } /// @@ -885,7 +885,7 @@ async ValueTask SendRawTopic(string queryString, bool pri var targetPort = ReattachInformation.Port; Byond.TopicSender.TopicResponse byondResponse; - using (await topicSendSemaphore.Lock(cancellationToken)) + using (await TopicSendSemaphore.Lock(cancellationToken)) byondResponse = await byondTopicSender.SendWithOptionalPriority( asyncDelayer, Logger, diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index acb1a095e03..c62fbd67b53 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -237,20 +237,33 @@ async ValueTask RunTest(bool useTrusted) await RunTest(false); } - async ValueTask SendTestTopic(string queryString, CancellationToken cancellationToken) + ValueTask SendTestTopic(string queryString, CancellationToken cancellationToken) + => SendTestTopic(queryString, topicClient, instanceManager.GetInstanceReference(instanceClient.Metadata), FindTopicPort(), cancellationToken); + + public static async ValueTask SendTestTopic(string queryString, ITopicClient topicClient, IInstanceReference instanceReference, ushort topicPort, CancellationToken cancellationToken) { - using var loggerFactory = LoggerFactory.Create(builder => + using (instanceReference) { - builder.AddConsole(); - builder.SetMinimumLevel(LogLevel.Trace); - }); - return await topicClient.SendWithOptionalPriority( - new AsyncDelayer(), - loggerFactory.CreateLogger(), - queryString, - FindTopicPort(), - true, - cancellationToken); + using var loggerFactory = LoggerFactory.Create(builder => + { + builder.AddConsole(); + builder.SetMinimumLevel(LogLevel.Trace); + }); + + var watchdog = instanceReference?.Watchdog; + var session = (SessionController)watchdog?.GetType().GetMethod("GetActiveController", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(watchdog, null); + + using (session != null + ? await session.TopicSendSemaphore.Lock(cancellationToken) + : null) + return await topicClient.SendWithOptionalPriority( + new AsyncDelayer(), + loggerFactory.CreateLogger(), + queryString, + topicPort, + true, + cancellationToken); + } } async ValueTask BroadcastTest(CancellationToken cancellationToken) @@ -1335,8 +1348,8 @@ bool KillDD(bool require) } public Task TellWorldToReboot(bool waitForOnlineIfRestoring, CancellationToken cancellationToken, [CallerLineNumber]int source = 0) - => TellWorldToReboot2(instanceClient, topicClient, FindTopicPort(), waitForOnlineIfRestoring || testVersion.Engine.Value == EngineType.OpenDream, cancellationToken, source); - public static async Task TellWorldToReboot2(IInstanceClient instanceClient, ITopicClient topicClient, ushort topicPort, bool waitForOnlineIfRestoring, CancellationToken cancellationToken, [CallerLineNumber]int source = 0, [CallerFilePath]string path = null) + => TellWorldToReboot2(instanceClient, instanceManager, topicClient, FindTopicPort(), waitForOnlineIfRestoring || testVersion.Engine.Value == EngineType.OpenDream, cancellationToken, source); + public static async Task TellWorldToReboot2(IInstanceClient instanceClient, IInstanceManager instanceManager, ITopicClient topicClient, ushort topicPort, bool waitForOnlineIfRestoring, CancellationToken cancellationToken, [CallerLineNumber]int source = 0, [CallerFilePath]string path = null) { var daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken); Assert.IsNotNull(daemonStatus.StagedCompileJob); @@ -1344,13 +1357,7 @@ public static async Task TellWorldToReboot2(IInstanceClient System.Console.WriteLine($"TEST: Sending world reboot topic @ {path}#L{source}"); - var result = await topicClient.SendWithOptionalPriority( - new AsyncDelayer(), - Mock.Of(), - $"tgs_integration_test_special_tactics=1", - topicPort, - true, - cancellationToken); + var result = await SendTestTopic("tgs_integration_test_special_tactics=1", topicClient, instanceManager.GetInstanceReference(instanceClient.Metadata), topicPort, cancellationToken); Assert.AreEqual("ack", result.StringData); using var tempCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index bc0a8c5e5af..b027ca4b4f1 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -1532,12 +1532,11 @@ await FailFast( // test the reattach message queueing // for the code coverage really... - var topicRequestResult = await WatchdogTest.StaticTopicClient.SendWithOptionalPriority( - new AsyncDelayer(), - Mock.Of(), - $"tgs_integration_test_tactics6=1", + var topicRequestResult = await WatchdogTest.SendTestTopic( + "tgs_integration_test_tactics6=1", + WatchdogTest.StaticTopicClient, + null, mainDDPort, - true, cancellationToken); Assert.IsNotNull(topicRequestResult); @@ -1610,12 +1609,11 @@ await FailFast( var chatReadTask = instanceClient.ChatBots.List(null, cancellationToken); // Check the DMAPI got the channels again https://github.com/tgstation/tgstation-server/issues/1490 - topicRequestResult = await WatchdogTest.StaticTopicClient.SendWithOptionalPriority( - new AsyncDelayer(), - Mock.Of(), - $"tgs_integration_test_tactics7=1", + topicRequestResult = await WatchdogTest.SendTestTopic( + "tgs_integration_test_tactics7=1", + WatchdogTest.StaticTopicClient, + GetInstanceManager().GetInstanceReference(instanceClient.Metadata), mainDDPort, - true, cancellationToken); Assert.IsNotNull(topicRequestResult); @@ -1626,7 +1624,13 @@ await FailFast( Assert.AreEqual(connectedChannelCount, topicRequestResult.FloatData.Value); - dd = await WatchdogTest.TellWorldToReboot2(instanceClient, WatchdogTest.StaticTopicClient, mainDDPort, true, cancellationToken); + dd = await WatchdogTest.TellWorldToReboot2( + instanceClient, + GetInstanceManager(), + WatchdogTest.StaticTopicClient, + mainDDPort, + true, + cancellationToken); Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value); // if this assert fails, you likely have to crack open the debugger and read test_fail_reason.txt manually Assert.IsNull(dd.StagedCompileJob); From 768a91eabc674ac4ec674c0ca08be556c663b323 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 22:44:22 -0500 Subject: [PATCH 455/717] Cleanup a bunch of messages --- .../Components/StaticFiles/Configuration.cs | 47 +++++++++---------- .../Components/Watchdog/WatchdogBase.cs | 3 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs index f42b4cc7e2c..eecb350e43d 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs @@ -298,8 +298,7 @@ void ReadImpl() string GetFileSha() { var content = synchronousIOManager.ReadFile(path); - using var sha1 = SHA1.Create(); - return String.Join(String.Empty, sha1.ComputeHash(content).Select(b => b.ToString("x2", CultureInfo.InvariantCulture))); + return String.Join(String.Empty, SHA1.HashData(content).Select(b => b.ToString("x2", CultureInfo.InvariantCulture))); } var originalSha = GetFileSha(); @@ -406,12 +405,10 @@ await ValueTaskExtensions.WhenAll(entries.Select(async file = var fileName = ioManager.GetFileName(file); // need to normalize - bool ignored; - if (platformIdentifier.IsWindows) - ignored = ignoreFiles.Any(y => fileName.ToUpperInvariant() == y.ToUpperInvariant()); - else - ignored = ignoreFiles.Any(y => fileName == y); - + var fileComparison = platformIdentifier.IsWindows + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal; + var ignored = ignoreFiles.Any(y => fileName.Equals(y, fileComparison)); if (ignored) { logger.LogTrace("Ignoring static file {fileName}...", fileName); @@ -442,12 +439,14 @@ await ValueTaskExtensions.WhenAll(entries.Select(async file = using (var reader = new StringReader(ignoreFileText)) { cancellationToken.ThrowIfCancellationRequested(); - var line = await reader.ReadLineAsync(); + var line = await reader.ReadLineAsync(cancellationToken); if (!String.IsNullOrEmpty(line)) ignoreFiles.Add(line); } - await ValueTaskExtensions.WhenAll(SymlinkBase(true), SymlinkBase(false)); + var filesSymlinkTask = SymlinkBase(true); + var dirsSymlinkTask = SymlinkBase(false); + await ValueTaskExtensions.WhenAll(filesSymlinkTask, dirsSymlinkTask); } } @@ -615,7 +614,7 @@ public async ValueTask HandleEvent(EventType eventType, IEnumerable para scriptName => x.StartsWith(scriptName, StringComparison.Ordinal))) .ToList(); - if (!scriptFiles.Any()) + if (scriptFiles.Count == 0) { logger.LogTrace("No event scripts starting with \"{scriptName}\" detected", String.Join("\" or \"", scriptNames)); return; @@ -710,19 +709,19 @@ async Task ValidateCodeModsFolder() return; await ioManager.CreateDirectory(CodeModificationsSubdirectory, cancellationToken); - await ValueTaskExtensions.WhenAll( - ioManager.WriteAllBytes( - ioManager.ConcatPath( - CodeModificationsSubdirectory, - CodeModificationsHeadFile), - Encoding.UTF8.GetBytes(DefaultHeadInclude), - cancellationToken), - ioManager.WriteAllBytes( - ioManager.ConcatPath( - CodeModificationsSubdirectory, - CodeModificationsTailFile), - Encoding.UTF8.GetBytes(DefaultTailInclude), - cancellationToken)); + var headWriteTask = ioManager.WriteAllBytes( + ioManager.ConcatPath( + CodeModificationsSubdirectory, + CodeModificationsHeadFile), + Encoding.UTF8.GetBytes(DefaultHeadInclude), + cancellationToken); + var tailWriteTask = ioManager.WriteAllBytes( + ioManager.ConcatPath( + CodeModificationsSubdirectory, + CodeModificationsTailFile), + Encoding.UTF8.GetBytes(DefaultTailInclude), + cancellationToken); + await ValueTaskExtensions.WhenAll(headWriteTask, tailWriteTask); } return Task.WhenAll( diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index 60b3deb05fd..4fb3e1677f1 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -748,8 +748,9 @@ protected async ValueTask HandleEventImpl(EventType eventType, IEnumerable Date: Sat, 16 Dec 2023 22:45:12 -0500 Subject: [PATCH 456/717] Disable `IDE0028` and `IDE0301` --- build/analyzers.ruleset | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/build/analyzers.ruleset b/build/analyzers.ruleset index 237aa86fe45..e61e800d008 100644 --- a/build/analyzers.ruleset +++ b/build/analyzers.ruleset @@ -668,7 +668,9 @@ + + @@ -718,8 +720,8 @@ - - + + @@ -755,6 +757,7 @@ + @@ -956,8 +959,8 @@ - - + + From a9d21eccf746139b63787a932b4b201b2f2bc642 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 16 Dec 2023 22:47:56 -0500 Subject: [PATCH 457/717] Fix another style message --- .../Components/StaticFiles/Configuration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs index eecb350e43d..5e871c25511 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs @@ -71,7 +71,7 @@ sealed class Configuration : IConfiguration /// /// Map of s to the filename of the event scripts they trigger. /// - static readonly IReadOnlyDictionary> EventTypeScriptFileNameMap = new Dictionary>( + public static IReadOnlyDictionary> EventTypeScriptFileNameMap { get; } = new Dictionary>( Enum.GetValues(typeof(EventType)) .Cast() .Select( From 2cff33c5b39bc734db219911e05d2dc8045283ec Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 09:16:35 -0500 Subject: [PATCH 458/717] I am once again asking you to fix process output reading --- .../System/ProcessExecutor.cs | 78 ++++++++++--------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index 0deae3507a5..8df021f7959 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.IO; using System.Text; using System.Threading; @@ -7,7 +8,6 @@ using Microsoft.Extensions.Logging; -using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.IO; namespace Tgstation.Server.Host.System @@ -145,9 +145,6 @@ public IProcess LaunchProcess( if (readStandardHandles) { processStartTcs = new TaskCompletionSource(); - handle.StartInfo.RedirectStandardOutput = true; - handle.StartInfo.RedirectStandardError = true; - disposeCts = new CancellationTokenSource(); readTask = ConsumeReaders(handle, processStartTcs.Task, fileRedirect, disposeCts.Token); } @@ -228,11 +225,8 @@ public IProcess GetProcessByName(string name) /// A resulting in the program's output/error text if is , otherwise. async Task ConsumeReaders(global::System.Diagnostics.Process handle, Task startupAndPid, string fileRedirect, CancellationToken cancellationToken) { - var pid = await startupAndPid; - logger.LogTrace("Starting read for PID {pid}...", pid); - - var stdOutHandle = handle.StandardOutput; - var stdErrHandle = handle.StandardError; + handle.StartInfo.RedirectStandardOutput = true; + handle.StartInfo.RedirectStandardError = true; bool writingToFile; await using var fileStream = (writingToFile = fileRedirect != null) ? ioManager.CreateAsyncSequentialWriteStream(fileRedirect) : null; @@ -249,24 +243,31 @@ async Task ConsumeReaders(global::System.Diagnostics.Process handle, Tas }); var handlesOpen = 2; - async ValueTask DrainHandle(StreamReader reader) + async void DataReceivedHandler(object sender, DataReceivedEventArgs eventArgs) { - while (true) + var line = eventArgs.Data; + if (line == null) { - var line = await reader.ReadLineAsync(cancellationToken); - if (line == null) - { - var handlesRemaining = Interlocked.Decrement(ref handlesOpen); - if (handlesRemaining == 0) - dataChannel.Writer.Complete(); + var handlesRemaining = Interlocked.Decrement(ref handlesOpen); + if (handlesRemaining == 0) + dataChannel.Writer.Complete(); - break; - } + return; + } + try + { await dataChannel.Writer.WriteAsync(line, cancellationToken); } + catch (OperationCanceledException ex) + { + logger.LogWarning(ex, "Handle channel write interrupted!"); + } } + handle.OutputDataReceived += DataReceivedHandler; + handle.ErrorDataReceived += DataReceivedHandler; + async ValueTask OutputWriter() { var enumerable = dataChannel.Reader.ReadAllAsync(cancellationToken); @@ -289,28 +290,31 @@ async ValueTask OutputWriter() stringBuilder.AppendLine(text); } - try + var pid = await startupAndPid; + logger.LogTrace("Starting read for PID {pid}...", pid); + + using (cancellationToken.Register(() => dataChannel.Writer.TryComplete())) { - var outputWriterTask = OutputWriter(); - try + handle.BeginOutputReadLine(); + using (cancellationToken.Register(handle.CancelOutputRead)) { - var outputReadTask = DrainHandle(stdOutHandle); - var errorReadTask = DrainHandle(stdErrHandle); + handle.BeginErrorReadLine(); + using (cancellationToken.Register(handle.CancelErrorRead)) + { + try + { + await OutputWriter(); - await ValueTaskExtensions.WhenAll(outputReadTask, errorReadTask); - } - finally - { - await outputWriterTask; + logger.LogTrace("Finished read for PID {pid}", pid); + } + catch (OperationCanceledException ex) + { + logger.LogWarning(ex, "PID {pid} stream reading interrupted!", pid); + if (fileStream != null) + await writer.WriteLineAsync("-- Process detached, log truncated. This is likely due a to TGS restart --"); + } + } } - - logger.LogTrace("Finished read for PID {pid}", pid); - } - catch (OperationCanceledException ex) - { - logger.LogWarning(ex, "PID {pid} stream reading interrupted!", pid); - if (fileStream != null) - await writer.WriteLineAsync("-- Process detached, log truncated. This is likely due a to TGS restart --"); } return stringBuilder?.ToString(); From f775a0563b16e5432e4af3b27689f6e4ab86df64 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 10:33:48 -0500 Subject: [PATCH 459/717] Nullify `ChannelRepresentation` --- .../Components/Chat/ChannelRepresentation.cs | 22 +++++++++++++---- .../Chat/Providers/DiscordProvider.cs | 24 +++++++++---------- .../Components/Chat/Providers/IrcProvider.cs | 13 ++++------ .../Live/DummyChatProvider.cs | 13 ++++------ .../Live/Instance/WatchdogTest.cs | 4 +--- 5 files changed, 39 insertions(+), 37 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChannelRepresentation.cs b/src/Tgstation.Server.Host/Components/Chat/ChannelRepresentation.cs index aed43e08174..b7bed776d65 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChannelRepresentation.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChannelRepresentation.cs @@ -3,8 +3,6 @@ using Newtonsoft.Json; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat { /// @@ -32,12 +30,12 @@ public ulong RealId /// /// The user friendly name of the . /// - public string FriendlyName { get; set; } + public string FriendlyName { get; } /// /// The name of the connection the belongs to. /// - public string ConnectionName { get; set; } + public string ConnectionName { get; } /// /// If this is considered a channel for admin commands. @@ -52,11 +50,25 @@ public ulong RealId /// /// For user use. /// - public string Tag { get; set; } + public string? Tag { get; set; } /// /// If this channel supports embeds. /// public bool EmbedsSupported { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + /// The value of /. + public ChannelRepresentation(string connectionName, string friendlyName, ulong id) + { + ConnectionName = connectionName ?? throw new ArgumentNullException(nameof(connectionName)); + FriendlyName = friendlyName ?? throw new ArgumentNullException(nameof(friendlyName)); + Id = null!; + RealId = id; + } } } diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 3ee853f36c1..3b3b4699d33 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -541,12 +541,12 @@ public async Task RespondAsync(IMessageCreate messageCreateEvent, Cancel User = new ChatUser { RealId = messageCreateEvent.Author.ID.Value, - Channel = new ChannelRepresentation + Channel = new ChannelRepresentation( + pm ? messageCreateEvent.Author.Username : guildName, + channelResponse.Entity.Name.Value, + messageCreateEvent.ChannelID.Value) { - RealId = messageCreateEvent.ChannelID.Value, IsPrivateChannel = pm, - ConnectionName = pm ? messageCreateEvent.Author.Username : guildName, - FriendlyName = channelResponse.Entity.Name.Value, EmbedsSupported = true, // isAdmin and Tag populated by manager @@ -721,12 +721,12 @@ protected override async ValueTask DisconnectImpl(CancellationToken cancellation var connectionName = guildsResponse.Entity.Name; - var channelModel = new ChannelRepresentation + var channelModel = new ChannelRepresentation( + guildsResponse.Entity.Name, + discordChannelResponse.Entity.Name.Value, + channelId) { - RealId = channelId, IsAdminChannel = channelFromDB.IsAdminChannel == true, - ConnectionName = guildsResponse.Entity.Name, - FriendlyName = discordChannelResponse.Entity.Name.Value, IsPrivateChannel = false, Tag = channelFromDB.Tag, EmbedsSupported = true, @@ -776,13 +776,13 @@ protected override async ValueTask DisconnectImpl(CancellationToken cancellation // Add catch-all channel unmappedTasks.Add(Task.FromResult( - new ChannelRepresentation + new ChannelRepresentation( + "(Unknown Discord Guilds)", + "(Unknown Discord Channels)", + 0) { IsAdminChannel = channelIdZeroModel.IsAdminChannel.Value, - ConnectionName = "(Unknown Discord Guilds)", EmbedsSupported = true, - FriendlyName = "(Unknown Discord Channels)", - RealId = 0, Tag = channelIdZeroModel.Tag, })); diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index b870536fb76..2db2f30376d 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -353,14 +353,11 @@ await SendMessage( dbChannel, new List { - new() + new(address, channelIdMap[id.Value], id.Value) { - RealId = id.Value, + Tag = dbChannel.Tag, IsAdminChannel = dbChannel.IsAdminChannel == true, - ConnectionName = address, - FriendlyName = channelIdMap[id.Value], IsPrivateChannel = false, - Tag = dbChannel.Tag, EmbedsSupported = false, }, }); @@ -532,16 +529,14 @@ ulong MapAndGetChannelId(Dictionary dicToCheck) channelId = isPrivate ? userId : MapAndGetChannelId(channelIdMap); } + var channelFriendlyName = isPrivate ? String.Format(CultureInfo.InvariantCulture, "PM: {0}", channelName) : channelName; var message = new Message { Content = e.Data.Message, User = new ChatUser { - Channel = new ChannelRepresentation + Channel = new ChannelRepresentation(address, channelFriendlyName, channelId) { - ConnectionName = address, - FriendlyName = isPrivate ? String.Format(CultureInfo.InvariantCulture, "PM: {0}", channelName) : channelName, - RealId = channelId, IsPrivateChannel = isPrivate, EmbedsSupported = false, diff --git a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs index 2edb4686eda..7aa9d531d6b 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs @@ -188,14 +188,14 @@ private ChannelRepresentation CreateChannel(ChatChannel channel) else channelId = (ulong)channel.IrcChannel.GetHashCode(); - var entry = new ChannelRepresentation + var entry = new ChannelRepresentation( + $"Connection_{channelId}", + $"(Friendly) Channel_ID_{channelId}", + channelId) { IsAdminChannel = channel.IsAdminChannel.Value, - ConnectionName = $"Connection_{channelId}", EmbedsSupported = ChatBot.Provider.Value != Api.Models.ChatProvider.Irc, - FriendlyName = $"(Friendly) Channel_ID_{channelId}", IsPrivateChannel = false, - RealId = channelId, Tag = channel.Tag, }; @@ -253,12 +253,9 @@ async Task RandomMessageLoop(CancellationToken cancellationToken) } while (knownChannels.ContainsKey(channelId)); - channel = new ChannelRepresentation + channel = new ChannelRepresentation($"{username}_Connection", $"{username}_Channel", channelId) { - RealId = channelId, IsPrivateChannel = true, - ConnectionName = $"{username}_Connection", - FriendlyName = $"{username}_Channel", EmbedsSupported = ChatBot.Provider.Value != Api.Models.ChatProvider.Irc, // isAdmin and Tag populated by manager diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index bcde5714ff2..fda9c94cce9 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -983,12 +983,10 @@ async Task WhiteBoxChatCommandTest(CancellationToken cancellationToken) { var mockChatUser = new ChatUser { - Channel = new ChannelRepresentation + Channel = new ChannelRepresentation("test_connection", "Test Connection", 0) { IsAdminChannel = true, - ConnectionName = "test_connection", EmbedsSupported = true, - FriendlyName = "Test Connection", Id = "test_channel_id", IsPrivateChannel = false, }, From 5eef0905116649934ad2f9c4ecb29da3e8bfc826 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 09:53:50 -0500 Subject: [PATCH 460/717] Suppress OD build output in CI --- .../Components/Engine/OpenDreamInstaller.cs | 18 ++++++++++++++---- .../Configuration/GeneralConfiguration.cs | 5 +++++ src/Tgstation.Server.Host/appsettings.yml | 1 + .../Live/LiveTestingServer.cs | 1 + 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 6b356ba5391..b8ffc98334b 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -230,18 +230,28 @@ await HandleExtremelyLongPathOperation( shortenedPath, $"run -c Release --project OpenDreamPackageTool -- --tgs -o {shortenedDeployPath}", null, - true, - true); + !GeneralConfiguration.OpenDreamSuppressInstallOutput, + !GeneralConfiguration.OpenDreamSuppressInstallOutput); using (cancellationToken.Register(() => buildProcess.Terminate())) buildExitCode = await buildProcess.Lifetime; - Logger.LogTrace("OD build complete, waiting for output..."); + string output; + + if (!GeneralConfiguration.OpenDreamSuppressInstallOutput) + { + var buildOutputTask = buildProcess.GetCombinedOutput(cancellationToken); + if (!buildOutputTask.IsCompleted) + Logger.LogTrace("OD build complete, waiting for output..."); + output = await buildOutputTask; + } + else + output = ""; Logger.LogDebug( "OpenDream build exited with code {exitCode}:{newLine}{output}", buildExitCode, Environment.NewLine, - await buildProcess.GetCombinedOutput(cancellationToken)); + output); }, sourcePath, cancellationToken); diff --git a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs index f33ef79b11c..8e2fe595796 100644 --- a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs @@ -145,6 +145,11 @@ public sealed class GeneralConfiguration : ServerInformationBase /// public string OpenDreamGitTagPrefix { get; set; } = DefaultOpenDreamGitTagPrefix; + /// + /// If the dotnet output of creating an OpenDream installation should be suppressed. Known to cause issues in CI. + /// + public bool OpenDreamSuppressInstallOutput { get; set; } + /// /// Initializes a new instance of the class. /// diff --git a/src/Tgstation.Server.Host/appsettings.yml b/src/Tgstation.Server.Host/appsettings.yml index 60624d36172..56f87f2169e 100644 --- a/src/Tgstation.Server.Host/appsettings.yml +++ b/src/Tgstation.Server.Host/appsettings.yml @@ -18,6 +18,7 @@ General: DeploymentDirectoryCopyTasksPerCore: 100 # Maximum number of concurrent file copy operations PER available CPU core OpenDreamGitUrl: https://github.com/OpenDreamProject/OpenDream # The repository to retrieve OpenDream from OpenDreamGitTagPrefix: v # The prefix to the OpenDream semver as tags appear in the git repository + OpenDreamSuppressInstallOutput: false # Suppress the dotnet output of creating an OpenDream installation. Known to cause hangs in CI. Session: HighPriorityLiveDreamDaemon: false # If DreamDaemon instances should run as higher priority processes LowPriorityDeploymentProcesses: true # If TGS Deployments should run as lower priority processes diff --git a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs index 61a7a36176c..645edac147d 100644 --- a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs +++ b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs @@ -154,6 +154,7 @@ public LiveTestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth $"General:SkipAddingByondFirewallException={!TestingUtils.RunningInGitHubActions}", $"General:OpenDreamGitUrl={OpenDreamUrl}", $"Security:TokenExpiryMinutes=120", // timeouts are useless for us + $"General:OpenDreamSuppressInstallOutput={TestingUtils.RunningInGitHubActions}", }; swarmArgs = new List(); From 360490189f73d158f5ac4a79690be4d482a6fa64 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 14:41:18 -0500 Subject: [PATCH 461/717] Nullify `ChatManagerFactory` --- .../Components/Chat/ChatManagerFactory.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManagerFactory.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManagerFactory.cs index 7e9c09eb423..a1697a97117 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManagerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManagerFactory.cs @@ -7,8 +7,7 @@ using Tgstation.Server.Host.Components.Chat.Commands; using Tgstation.Server.Host.Components.Chat.Providers; using Tgstation.Server.Host.Core; - -#nullable disable +using Tgstation.Server.Host.Models; namespace Tgstation.Server.Host.Components.Chat { @@ -56,6 +55,6 @@ public IChatManager CreateChatManager( serverControl, loggerFactory, loggerFactory.CreateLogger(), - initialChatBots.Where(x => x.Enabled.Value)); + initialChatBots.Where(x => x.Require(y => y.Enabled))); } } From 4ba1f591c689a7739ec3c4c59a161549aa9c2934 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 14:42:31 -0500 Subject: [PATCH 462/717] Nullify `ChatTrackingContext` --- .../Components/Chat/ChatTrackingContext.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs b/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs index bf6ab315ed9..1378714e240 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs @@ -8,8 +8,6 @@ using Tgstation.Server.Host.Components.Chat.Commands; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat { /// @@ -75,12 +73,12 @@ public IEnumerable CustomCommands /// /// The if any. /// - IChannelSink channelSink; + IChannelSink? channelSink; /// /// The to run when d. /// - Action onDispose; + Action? onDispose; /// /// Backing field for . From f36349fb6fd6c541a84dc20fbf28d17323a504d3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 14:43:16 -0500 Subject: [PATCH 463/717] Nullify `CommandFactory` --- .../Components/Chat/Commands/CommandFactory.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs index 28eecb26286..a575ec9c87d 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/CommandFactory.cs @@ -8,8 +8,6 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Commands { /// @@ -48,7 +46,7 @@ sealed class CommandFactory : ICommandFactory /// /// The for the . /// - IWatchdog watchdog; + IWatchdog? watchdog; /// /// Initializes a new instance of the class. From b1810e5a678e923284d51525556ee49cb2a721a4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 14:49:37 -0500 Subject: [PATCH 464/717] Nullify `CustomCommand` --- .../Components/Chat/Commands/CustomCommand.cs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/CustomCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/CustomCommand.cs index b11d22d5ef4..9492e925d72 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/CustomCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/CustomCommand.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Components.Interop; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Commands { /// @@ -14,18 +12,31 @@ namespace Tgstation.Server.Host.Components.Chat.Commands public sealed class CustomCommand : ICommand { /// - public string Name { get; set; } + public string Name { get; } /// - public string HelpText { get; set; } + public string HelpText { get; } /// - public bool AdminOnly { get; set; } + public bool AdminOnly { get; } /// /// The for the . /// - ICustomCommandHandler handler; + ICustomCommandHandler? handler; + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + /// The value of . + public CustomCommand(string name, string helpText, bool adminOnly) + { + Name = name ?? throw new ArgumentNullException(nameof(name)); + HelpText = helpText ?? throw new ArgumentNullException(nameof(helpText)); + AdminOnly = adminOnly; + } /// /// Set a new . From 83e0c2046a5b24119b04393387bdcd3260f45c94 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 15:00:03 -0500 Subject: [PATCH 465/717] Improved `EngineVersion` parsing --- .../Models/EngineVersion.cs | 19 ++++++++++++++++++- .../Models/Internal/TestEngineVersion.cs | 8 ++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Api/Models/EngineVersion.cs b/src/Tgstation.Server.Api/Models/EngineVersion.cs index d4681faa60d..adaa90bcbf0 100644 --- a/src/Tgstation.Server.Api/Models/EngineVersion.cs +++ b/src/Tgstation.Server.Api/Models/EngineVersion.cs @@ -38,7 +38,7 @@ public sealed class EngineVersion : IEquatable public int? CustomIteration { get; set; } /// - /// Parses a stringified . + /// Attempts to parse a stringified . /// /// The input . /// The output . @@ -110,6 +110,23 @@ public static bool TryParse(string input, out EngineVersion? engineVersion) return true; } + /// + /// Parses a stringified . + /// + /// The input . + /// The output . + /// If the is not a valid stringified . + public static EngineVersion Parse(string input) + { + if (input == null) + throw new ArgumentNullException(nameof(input)); + + if (TryParse(input, out var engineVersion)) + return engineVersion!; + + throw new InvalidOperationException($"Invalid engine version: {input}"); + } + /// /// Initializes a new instance of the class. /// diff --git a/tests/Tgstation.Server.Api.Tests/Models/Internal/TestEngineVersion.cs b/tests/Tgstation.Server.Api.Tests/Models/Internal/TestEngineVersion.cs index a426927b01f..f13f09f3ff7 100644 --- a/tests/Tgstation.Server.Api.Tests/Models/Internal/TestEngineVersion.cs +++ b/tests/Tgstation.Server.Api.Tests/Models/Internal/TestEngineVersion.cs @@ -11,28 +11,36 @@ public sealed class TestEngineVersion public void TestParsing() { Assert.IsTrue(EngineVersion.TryParse("OpenDream-6894ba0702c1764d333eb52aa0cc211d62e2cb1c-1", out var version)); + Assert.IsNotNull(version); Assert.AreEqual(EngineType.OpenDream, version.Engine); Assert.AreEqual("6894ba0702c1764d333eb52aa0cc211d62e2cb1c", version.SourceSHA); Assert.IsNull(version.Version); Assert.AreEqual(1, version.CustomIteration); Assert.IsTrue(EngineVersion.TryParse("OpenDream-6894ba0702c1764d333eb52aa0cc211d62e2cb1c", out version)); + Assert.IsNotNull(version); Assert.AreEqual(EngineType.OpenDream, version.Engine); Assert.AreEqual("6894ba0702c1764d333eb52aa0cc211d62e2cb1c", version.SourceSHA); Assert.IsNull(version.Version); Assert.IsFalse(version.CustomIteration.HasValue); Assert.IsTrue(EngineVersion.TryParse("515.1616", out version)); + Assert.IsNotNull(version); Assert.AreEqual(EngineType.Byond, version.Engine); Assert.AreEqual(new Version(515, 1616), version.Version); Assert.IsNull(version.SourceSHA); Assert.IsFalse(version.CustomIteration.HasValue); Assert.IsTrue(EngineVersion.TryParse("515.1616.12", out version)); + Assert.IsNotNull(version); Assert.AreEqual(EngineType.Byond, version.Engine); Assert.AreEqual(new Version(515, 1616), version.Version); Assert.IsNull(version.SourceSHA); Assert.AreEqual(12, version.CustomIteration); + + Assert.IsFalse(EngineVersion.TryParse("x", out version)); + Assert.IsNull(version); + Assert.ThrowsException(() => EngineVersion.Parse("x")); } } } From 1d815498fc21087b0979bf9ec0258dd69a848f3b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 15:01:16 -0500 Subject: [PATCH 466/717] Nullify `EngineCommand` --- .../Components/Chat/Commands/EngineCommand.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs index 75a6e79e547..21789bb2586 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs @@ -8,8 +8,6 @@ using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Watchdog; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Commands { /// @@ -69,8 +67,7 @@ public ValueTask Invoke(string arguments, ChatUser user, Cancell Text = "None!", }); - if (!EngineVersion.TryParse(watchdog.ActiveCompileJob.EngineVersion, out engineVersion)) - throw new InvalidOperationException($"Invalid engine version: {watchdog.ActiveCompileJob.EngineVersion}"); + engineVersion = EngineVersion.Parse(watchdog.ActiveCompileJob.EngineVersion); } string text; @@ -78,10 +75,10 @@ public ValueTask Invoke(string arguments, ChatUser user, Cancell text = "None!"; else { - text = engineVersion.Engine.Value switch + text = engineVersion.Engine!.Value switch { EngineType.OpenDream => $"OpenDream: {engineVersion.SourceSHA}", - EngineType.Byond => $"BYOND {engineVersion.Version.Major}.{engineVersion.Version.Minor}", + EngineType.Byond => $"BYOND {engineVersion.Version!.Major}.{engineVersion.Version.Minor}", _ => throw new InvalidOperationException($"Invalid EngineType: {engineVersion.Engine.Value}"), }; From da10d0f1519418fdca04b7c3d4e6676c78fb1067 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 16:23:32 -0500 Subject: [PATCH 467/717] Double a test timeout --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index c62fbd67b53..7924638e4f6 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -782,7 +782,7 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke ourProcessHandler.Suspend(); global::System.Console.WriteLine($"WATCHDOG TEST {instanceClient.Metadata.Id}: FINISH PROCESS SUSPEND FOR HEALTH CHECK DEATH. WAITING FOR LIFETIME {ourProcessHandler.Id}."); - await Task.WhenAny(ourProcessHandler.Lifetime, Task.Delay(TimeSpan.FromMinutes(2), cancellationToken)); + await Task.WhenAny(ourProcessHandler.Lifetime, Task.Delay(TimeSpan.FromMinutes(4), cancellationToken)); Assert.IsTrue(ourProcessHandler.Lifetime.IsCompleted); var timeout = 20; From 4b4bdcf25afe7ba7490769bfcf141816156852a0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 16:27:36 -0500 Subject: [PATCH 468/717] Use larger page size here --- tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index 19be3fe30b5..f5edc04ea16 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -156,7 +156,10 @@ await permedUser.Instances.Update(new InstanceUpdateRequest Online = true, }, cancellationToken); - var jobs = await permedUser.Instances.CreateClient(instance).Jobs.List(null, cancellationToken); + var jobs = await permedUser.Instances.CreateClient(instance).Jobs.List(new PaginationSettings + { + PageSize = 100 + }, cancellationToken); if (wasOffline) await permedUser.Instances.Update(new InstanceUpdateRequest { From 577ecb0d0243f836933c7998cd9a96696baa4356 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 16:27:43 -0500 Subject: [PATCH 469/717] Show all duplicated jobs --- tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index f5edc04ea16..84985b6a9bf 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -179,7 +179,7 @@ await permedUser.Instances.Update(new InstanceUpdateRequest var uniqueAllJobs = groups.Select(x => x.First()).ToList(); static string JobListFormatter(IEnumerable jobs) => String.Join(Environment.NewLine, jobs.Select(x => $"- I:{x.InstanceId}|JID:{x.Id}|JC:{x.JobCode}|Desc:{x.Description}")); - Assert.AreEqual(allJobs.Count, uniqueAllJobs.Count, $"Duplicated Jobs:{Environment.NewLine}{JobListFormatter(groups.Where(x => x.Count() > 1).Select(x => x.First()))}"); + Assert.AreEqual(allJobs.Count, uniqueAllJobs.Count, $"Duplicated Jobs:{Environment.NewLine}{JobListFormatter(groups.Where(x => x.Count() > 1).SelectMany(x => x))}"); var missableMissedJobs = 0; foreach (var job in allJobs) From 93da4d87664ea1cb16a69b20713bf221a51d1dc1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 16:32:51 -0500 Subject: [PATCH 470/717] More robust test port allocation --- .../Live/TestLiveServer.cs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index b027ca4b4f1..8c81e5451df 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -54,12 +54,12 @@ public sealed class TestLiveServer { public static readonly Version TestUpdateVersion = new(5, 11, 0); - static readonly ushort mainDDPort = FreeTcpPort(); - static readonly ushort mainDMPort = FreeTcpPort(mainDDPort); - static readonly ushort compatDMPort = FreeTcpPort(mainDDPort, mainDMPort); - static readonly ushort compatDDPort = FreeTcpPort(mainDDPort, mainDMPort, compatDMPort); - static readonly ushort odDMPort = FreeTcpPort(mainDDPort, mainDMPort, compatDMPort, compatDDPort); - static readonly ushort odDDPort = FreeTcpPort(mainDDPort, mainDMPort, compatDMPort, compatDDPort, odDMPort); + static readonly Lazy odDMPort = new Lazy(() => FreeTcpPort()); + static readonly Lazy odDDPort = new Lazy(() => FreeTcpPort(odDMPort.Value)); + static readonly Lazy compatDMPort = new Lazy(() => FreeTcpPort(odDDPort.Value, odDMPort.Value)); + static readonly Lazy compatDDPort = new Lazy(() => FreeTcpPort(odDDPort.Value, odDMPort.Value, compatDMPort.Value)); + static readonly Lazy mainDDPort = new Lazy(() => FreeTcpPort(odDDPort.Value, odDMPort.Value, compatDMPort.Value, compatDDPort.Value)); + static readonly Lazy mainDMPort = new Lazy(() => FreeTcpPort(odDDPort.Value, odDMPort.Value, compatDMPort.Value, compatDDPort.Value, mainDDPort.Value)); readonly ServerClientFactory clientFactory = new (new ProductHeaderValue(Assembly.GetExecutingAssembly().GetName().Name, Assembly.GetExecutingAssembly().GetName().Version.ToString())); @@ -167,7 +167,7 @@ static ushort FreeTcpPort(params ushort[] usedPorts) result = (ushort)((IPEndPoint)l.LocalEndpoint).Port; } - while (usedPorts.Contains(result)); + while (usedPorts.Contains(result) || result < 10000); } finally { @@ -1457,8 +1457,8 @@ await instanceTest await edgeODVersionTask, server.OpenDreamUrl, firstAdminClient.Instances.CreateClient(odInstance), - odDMPort, - odDDPort, + odDMPort.Value, + odDDPort.Value, server.HighPriorityDreamDaemon, server.UsingBasicWatchdog, cancellationToken); @@ -1484,8 +1484,8 @@ await instanceTest }, server.OpenDreamUrl, firstAdminClient.Instances.CreateClient(compatInstance), - compatDMPort, - compatDDPort, + compatDMPort.Value, + compatDDPort.Value, server.HighPriorityDreamDaemon, server.UsingBasicWatchdog, cancellationToken)); @@ -1497,8 +1497,8 @@ await FailFast( instanceTest .RunTests( instanceClient, - mainDMPort, - mainDDPort, + mainDMPort.Value, + mainDDPort.Value, server.HighPriorityDreamDaemon, server.LowPriorityDeployments, server.UsingBasicWatchdog, @@ -1536,7 +1536,7 @@ await FailFast( "tgs_integration_test_tactics6=1", WatchdogTest.StaticTopicClient, null, - mainDDPort, + mainDDPort.Value, cancellationToken); Assert.IsNotNull(topicRequestResult); @@ -1613,7 +1613,7 @@ await FailFast( "tgs_integration_test_tactics7=1", WatchdogTest.StaticTopicClient, GetInstanceManager().GetInstanceReference(instanceClient.Metadata), - mainDDPort, + mainDDPort.Value, cancellationToken); Assert.IsNotNull(topicRequestResult); @@ -1628,7 +1628,7 @@ await FailFast( instanceClient, GetInstanceManager(), WatchdogTest.StaticTopicClient, - mainDDPort, + mainDDPort.Value, true, cancellationToken); @@ -1687,7 +1687,7 @@ async Task WaitForInitialJobs(IInstanceClient instanceClient) Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value); var compileJob = await instanceClient.DreamMaker.Compile(cancellationToken); - await using var wdt = new WatchdogTest(edgeVersion, instanceClient, GetInstanceManager(), (ushort)server.ApiUrl.Port, server.HighPriorityDreamDaemon, mainDDPort, server.UsingBasicWatchdog); + await using var wdt = new WatchdogTest(edgeVersion, instanceClient, GetInstanceManager(), (ushort)server.ApiUrl.Port, server.HighPriorityDreamDaemon, mainDDPort.Value, server.UsingBasicWatchdog); await wdt.WaitForJob(compileJob, 30, false, null, cancellationToken); dd = await instanceClient.DreamDaemon.Read(cancellationToken); @@ -1730,7 +1730,7 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest Assert.AreEqual(WatchdogStatus.Online, currentDD.Status); Assert.AreEqual(expectedStaged, currentDD.StagedCompileJob.Job.Id.Value); - await using var wdt = new WatchdogTest(edgeVersion, instanceClient, GetInstanceManager(), (ushort)server.ApiUrl.Port, server.HighPriorityDreamDaemon, mainDDPort, server.UsingBasicWatchdog); + await using var wdt = new WatchdogTest(edgeVersion, instanceClient, GetInstanceManager(), (ushort)server.ApiUrl.Port, server.HighPriorityDreamDaemon, mainDDPort.Value, server.UsingBasicWatchdog); currentDD = await wdt.TellWorldToReboot(false, cancellationToken); Assert.AreEqual(expectedStaged, currentDD.ActiveCompileJob.Job.Id.Value); Assert.IsNull(currentDD.StagedCompileJob); From 638418534e15bf3364ef2cde45f84b3078017bd5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 16:41:26 -0500 Subject: [PATCH 471/717] Fix `DummyChatProvider` interference with health check tests --- .../Tgstation.Server.Tests/Live/DummyChatProvider.cs | 4 ++++ .../Live/Instance/WatchdogTest.cs | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs index 2edb4686eda..14cc51dd4d9 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs @@ -44,6 +44,8 @@ sealed class DummyChatProvider : Provider ulong channelIdAllocator; + public static Task MessageGuard = Task.CompletedTask; + static IAsyncDelayer CreateMockDelayer() { // at time of writing, this is used exclusively for the reconnection interval which works in minutes @@ -219,6 +221,8 @@ async Task RandomMessageLoop(CancellationToken cancellationToken) var delay = random.Next(0, 10000); await Task.Delay(delay, cancellationToken); + await MessageGuard; + // %5 chance to disconnect randomly if (enableRandomDisconnections != 0 && random.Next(0, 100) > 95) connected = false; diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 7924638e4f6..c2fa31ba31a 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -165,9 +165,21 @@ await Task.WhenAll( await RunLongRunningTestThenUpdateWithNewDme(cancellationToken); await RunLongRunningTestThenUpdateWithByondVersionSwitch(cancellationToken); + // no chatty bullshit while we test health checks + var tcs = new TaskCompletionSource(); + var oldTask = Interlocked.Exchange(ref DummyChatProvider.MessageGuard, tcs.Task); + await RunHealthCheckTest(true, cancellationToken); await RunHealthCheckTest(false, cancellationToken); + async void Cleanup() + { + await oldTask; + tcs.SetResult(); + } + + Cleanup(); + await InteropTestsForLongRunningDme(cancellationToken); await instanceClient.DreamDaemon.Update(new DreamDaemonRequest From 2bb85b6aeaea0074770287259dae5385236338d1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 18:17:21 -0500 Subject: [PATCH 472/717] Simpler test port allocation --- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 8c81e5451df..6edee102eab 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -147,8 +147,12 @@ static bool TerminateAllEngineServers() static ushort FreeTcpPort(params ushort[] usedPorts) { + var portList = new ushort[] { 42069, 42070, 42071, 42072, 42073, 42074 }; + return portList.First(x => !usedPorts.Contains(x)); + /* ushort result; var listeners = new List(); + try { do @@ -177,6 +181,7 @@ static ushort FreeTcpPort(params ushort[] usedPorts) } } return result; + */ } [ClassInitialize] From b4831b63f6b4fe76b5a6207d615664d9c5c7cea8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 19:43:57 -0500 Subject: [PATCH 473/717] Nullify `ICommand` --- src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs index c5d4e3ef3ea..766f29b6c00 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/ICommand.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.Components.Interop; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Commands { /// From de637293f0f0e7a06c257fbf226f2126bb63333b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 19:44:09 -0500 Subject: [PATCH 474/717] Nullify `ICommandFactory` --- .../Components/Chat/Commands/ICommandFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/ICommandFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/ICommandFactory.cs index 1cc91c7ada3..c3ffa50d74c 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/ICommandFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/ICommandFactory.cs @@ -1,7 +1,5 @@ using System.Collections.Generic; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Commands { /// From 06b8dc9599497e9d35bc303b5bfc499aa05a7c35 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 19:45:07 -0500 Subject: [PATCH 475/717] Nullify `KekCommand` --- .../Components/Chat/Commands/KekCommand.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/KekCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/KekCommand.cs index f5ef18e1d99..a41278ae0aa 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/KekCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/KekCommand.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.Components.Interop; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Commands { /// From 54b6dc2423023a398f8ee00fccf1c17a2f0bfb01 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 19:47:31 -0500 Subject: [PATCH 476/717] Nullify `PullRequestsCommand` --- .../Components/Chat/Commands/PullRequestsCommand.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs index 990b5bdc11c..c4022d95d77 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs @@ -13,8 +13,6 @@ using Tgstation.Server.Host.Components.Watchdog; using Tgstation.Server.Host.Database; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Commands { /// @@ -83,7 +81,7 @@ public PullRequestsCommand( #pragma warning disable CA1506 public async ValueTask Invoke(string arguments, ChatUser user, CancellationToken cancellationToken) { - IEnumerable results = null; + IEnumerable results; var splits = arguments.Split(' '); var hasRepo = splits.Any(x => x.Equals("--repo", StringComparison.OrdinalIgnoreCase)); var hasStaged = splits.Any(x => x.Equals("--staged", StringComparison.OrdinalIgnoreCase)); @@ -114,6 +112,7 @@ public async ValueTask Invoke(string arguments, ChatUser user, C head = repo.Head; } + results = null!; await databaseContextFactory.UseContext( async db => results = await db .RevisionInformations @@ -155,7 +154,7 @@ await databaseContextFactory.UseContext( : String.Join( ", ", results.Select( - x => $"#{x.Number} at {x.TargetCommitSha[..7]}")), + x => $"#{x.Number} at {x.TargetCommitSha![..7]}")), }; } #pragma warning restore CA1506 From 8ef36dc4e3612de7ba09e5b54db2fc7c1ce0dfc0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 19:48:18 -0500 Subject: [PATCH 477/717] Nullify `RevisionCommand` --- .../Components/Chat/Commands/RevisionCommand.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/RevisionCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/RevisionCommand.cs index 60c12f9fc35..39ed128d591 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/RevisionCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/RevisionCommand.cs @@ -9,8 +9,6 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Components.Watchdog; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Commands { /// @@ -77,7 +75,7 @@ public async ValueTask Invoke(string arguments, ChatUser user, C { Text = "Server offline!", }; - result = watchdog.ActiveCompileJob?.RevisionInformation.OriginCommitSha; + result = watchdog.ActiveCompileJob?.RevisionInformation.OriginCommitSha!; } return new MessageContent From 1f1c7914d70687fdf9e7b3ccfe580e6610d6944b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 20:58:09 -0500 Subject: [PATCH 478/717] Fix a race condition with starting the server and bridge requests --- src/Tgstation.Server.Host/Components/InstanceManager.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index bf2b5dbba09..8f761627535 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -611,10 +611,11 @@ async ValueTask EnumerateInstances(IDatabaseContext databaseContext) await Task.WhenAll(instanceOnliningTasks); - jobService.Activate(this); - logger.LogInformation("Server ready!"); readyTcs.SetResult(); + + // this needs to happen after the HTTP API opens with readyTcs otherwise it can race and cause failed bridge requests with 503's + jobService.Activate(this); } catch (OperationCanceledException ex) { From 3ab14c99a65b8a44655dd38c49fd1dbd6b2d1c09 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 21:38:54 -0500 Subject: [PATCH 479/717] Nullify `IChannelSink` --- src/Tgstation.Server.Host/Components/Chat/IChannelSink.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/IChannelSink.cs b/src/Tgstation.Server.Host/Components/Chat/IChannelSink.cs index 78dbee1d738..e9e366902e4 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChannelSink.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChannelSink.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat { /// From cef33be32c7ffd4f623d7c6b4d81c15fe43bdaaa Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 21:40:08 -0500 Subject: [PATCH 480/717] Nullify `VersionCommand` --- .../Components/Chat/Commands/VersionCommand.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/VersionCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/VersionCommand.cs index 5857f6fea7e..60e7f9e9a17 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/VersionCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/VersionCommand.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Commands { /// From 3c7cf0360f4b84bd03d3eb9ce0e0685058343fb3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 21:43:19 -0500 Subject: [PATCH 481/717] Cleanup a `ValueTask` message --- .../Components/InstanceManager.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index 8f761627535..af7a3d7c814 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -353,7 +353,7 @@ public async ValueTask OfflineInstance(Models.Instance metadata, Models.User use await container.OnZeroReferences.WaitAsync(cancellationToken); // we are the one responsible for cancelling his jobs - var tasks = new List>(); + ValueTask groupedTask = default; await databaseContextFactory.UseContext( async db => { @@ -363,11 +363,13 @@ await databaseContextFactory.UseContext( .Where(x => x.Instance.Id == metadata.Id && !x.StoppedAt.HasValue) .Select(x => new Models.Job(x.Id.Value)) .ToListAsync(cancellationToken); - foreach (var job in jobs) - tasks.Add(jobService.CancelJob(job, user, true, cancellationToken)); + + groupedTask = ValueTaskExtensions.WhenAll( + jobs.Select(job => jobService.CancelJob(job, user, true, cancellationToken)), + jobs.Count); }); - await ValueTaskExtensions.WhenAll(tasks); + await groupedTask; } catch { From 8c34cf83d987dee341327c3d29ad128d258a1782 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 21:44:45 -0500 Subject: [PATCH 482/717] Nullify `DiscordMessage` --- .../Components/Chat/Providers/DiscordMessage.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordMessage.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordMessage.cs index 4d55e31d85e..b0b3fbb56eb 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordMessage.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordMessage.cs @@ -1,8 +1,6 @@ using Remora.Discord.API.Abstractions.Objects; using Remora.Rest.Core; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Providers { /// From ee16007c64a21c69cd674a4f1fd09c61fc47e11a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 21:47:38 -0500 Subject: [PATCH 483/717] Cleanup some collection initializations --- .../Components/Chat/Providers/DiscordProvider.cs | 6 +++--- src/Tgstation.Server.Host/Core/Application.cs | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 3b3b4699d33..20432e68d0f 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -60,13 +60,13 @@ public override string BotMention /// /// The s supported by the for mapping. /// - static readonly ChannelType[] SupportedGuildChannelTypes = new[] - { + static readonly ChannelType[] SupportedGuildChannelTypes = + [ ChannelType.GuildText, ChannelType.GuildAnnouncement, ChannelType.PrivateThread, ChannelType.PublicThread, - }; + ]; /// /// The for the . diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 03e14ed6a25..202b098d7c8 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Threading.Tasks; using Cyberboss.AspNetCore.AsyncInitializer; @@ -546,7 +545,7 @@ public void Configure( else if (controlPanelConfiguration.AllowedOrigins?.Count > 0) { logger.LogTrace("Access-Control-Allow-Origin: {allowedOrigins}", String.Join(',', controlPanelConfiguration.AllowedOrigins)); - corsBuilder = builder => builder.WithOrigins(controlPanelConfiguration.AllowedOrigins.ToArray()); + corsBuilder = builder => builder.WithOrigins([.. controlPanelConfiguration.AllowedOrigins]); } var originalBuilder = corsBuilder; From b225cbcf9e49d1d1b987bae10c92ec13f86f43b0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 21:47:57 -0500 Subject: [PATCH 484/717] Nullify `IDiscordResponders` --- .../Components/Chat/Providers/IDiscordResponders.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IDiscordResponders.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IDiscordResponders.cs index 3ca8ec9d42e..d0c320fa9e0 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IDiscordResponders.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IDiscordResponders.cs @@ -1,8 +1,6 @@ using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.Gateway.Responders; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Providers { /// From a574487235e8c16c7779cd0eba6a113e80ed3d53 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 21:49:53 -0500 Subject: [PATCH 485/717] Nullify `IProvider` --- .../Components/Chat/Providers/IProvider.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs index 0fc6beeb299..01b0d29a5e8 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Providers { /// @@ -47,7 +45,7 @@ interface IProvider : IAsyncDisposable /// The for the operation. /// A resulting in the next available or if the needed to reconnect. /// Note that private messages will come in the form of s not returned in . - Task NextMessage(CancellationToken cancellationToken); + Task NextMessage(CancellationToken cancellationToken); /// /// Gracefully disconnects the provider. Permanently stops the reconnection timer. @@ -67,12 +65,12 @@ interface IProvider : IAsyncDisposable /// /// Send a message to the . /// - /// The to reply to. + /// The optional to reply to. /// The . /// The to send to. /// The for the operation. /// A representing the running operation. - ValueTask SendMessage(Message replyTo, MessageContent message, ulong channelId, CancellationToken cancellationToken); + ValueTask SendMessage(Message? replyTo, MessageContent message, ulong channelId, CancellationToken cancellationToken); /// /// Set the interval at which the provider starts jobs to try to reconnect. @@ -98,8 +96,8 @@ ValueTask>>> SendUpdateMess Models.RevisionInformation revisionInformation, Api.Models.EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, - string gitHubOwner, - string gitHubRepo, + string? gitHubOwner, + string? gitHubRepo, ulong channelId, bool localCommitPushed, CancellationToken cancellationToken); From c88d837d693aee9d51bb059b92ea00d91a14bf37 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 21:50:08 -0500 Subject: [PATCH 486/717] Nullify `IProviderFactory` --- .../Components/Chat/Providers/IProviderFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IProviderFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IProviderFactory.cs index fea864ea717..d79e0bb7d5c 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IProviderFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IProviderFactory.cs @@ -1,7 +1,5 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Providers { /// From 81ef6191d5b270dbd0742c2daf6f2756bd94d4a9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 21:55:36 -0500 Subject: [PATCH 487/717] Nullify `Message` --- .../Components/Chat/Providers/DiscordMessage.cs | 14 ++++++++++++++ .../Chat/Providers/DiscordProvider.cs | 10 ++++------ .../Components/Chat/Providers/IrcProvider.cs | 8 +++----- .../Components/Chat/Providers/Message.cs | 17 ++++++++++++++--- .../Live/DummyChatProvider.cs | 7 +------ 5 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordMessage.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordMessage.cs index b0b3fbb56eb..565d78d654d 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordMessage.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordMessage.cs @@ -12,5 +12,19 @@ sealed class DiscordMessage : Message /// The of the source . /// public Optional MessageReference { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + /// The value of . + public DiscordMessage(ChatUser user, string content, Optional messageReference) + : base( + user, + content) + { + MessageReference = messageReference; + } } } diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 20432e68d0f..3a89c2245c1 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -534,11 +534,8 @@ public async Task RespondAsync(IMessageCreate messageCreateEvent, Cancel messageGuildResponse.LogFormat()); } - var result = new DiscordMessage - { - MessageReference = messageReference, - Content = content, - User = new ChatUser + var result = new DiscordMessage( + new ChatUser { RealId = messageCreateEvent.Author.ID.Value, Channel = new ChannelRepresentation( @@ -554,7 +551,8 @@ public async Task RespondAsync(IMessageCreate messageCreateEvent, Cancel FriendlyName = messageCreateEvent.Author.Username, Mention = NormalizeMentions($"<@{messageCreateEvent.Author.ID}>"), }, - }; + content, + messageReference); EnqueueMessage(result); return Result.FromSuccess(); diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index 2db2f30376d..70665bf6953 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -530,10 +530,8 @@ ulong MapAndGetChannelId(Dictionary dicToCheck) } var channelFriendlyName = isPrivate ? String.Format(CultureInfo.InvariantCulture, "PM: {0}", channelName) : channelName; - var message = new Message - { - Content = e.Data.Message, - User = new ChatUser + var message = new Message( + new ChatUser { Channel = new ChannelRepresentation(address, channelFriendlyName, channelId) { @@ -546,7 +544,7 @@ ulong MapAndGetChannelId(Dictionary dicToCheck) RealId = userId, Mention = username, }, - }; + e.Data.Message); EnqueueMessage(message); } diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/Message.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/Message.cs index f410514b807..c9084657fcb 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/Message.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/Message.cs @@ -1,4 +1,4 @@ -#nullable disable +using System; namespace Tgstation.Server.Host.Components.Chat.Providers { @@ -10,11 +10,22 @@ class Message /// /// The text of the message. /// - public string Content { get; set; } + public string Content { get; } /// /// The who sent the . /// - public ChatUser User { get; set; } + public ChatUser User { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + public Message(ChatUser user, string content) + { + User = user ?? throw new ArgumentNullException(nameof(user)); + Content = content ?? throw new ArgumentNullException(nameof(content)); + } } } diff --git a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs index 160af5010c2..8997c228415 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs @@ -315,13 +315,8 @@ async Task RandomMessageLoop(CancellationToken cancellationToken) else content = $"{content} embeds_test"; // NEVER send the response_overload_test, it causes so much havoc in CI and we test it manually - EnqueueMessage(new Message - { - Content = content, - User = sender, - }); + EnqueueMessage(new Message(sender, content)); } - } catch (OperationCanceledException) { From eb2e34fb0b545c928c4639f95836b00f51dde5d5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 21:58:46 -0500 Subject: [PATCH 488/717] Nullify `Provider` --- .../Components/Chat/Providers/Provider.cs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs index 1a036d7ffdc..da4deecd111 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs @@ -11,8 +11,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Providers { /// @@ -44,7 +42,7 @@ abstract class Provider : IProvider /// /// of received s. /// - readonly Queue messageQueue; + readonly Queue messageQueue; /// /// The backing for . @@ -64,12 +62,12 @@ abstract class Provider : IProvider /// /// The auto reconnect . /// - Task reconnectTask; + Task? reconnectTask; /// /// for . /// - CancellationTokenSource reconnectCts; + CancellationTokenSource? reconnectCts; /// /// Get the prefix for messages about deployments. @@ -98,7 +96,7 @@ protected Provider(IJobManager jobManager, IAsyncDelayer asyncDelayer, ILogger

(); + messageQueue = new Queue(); nextMessage = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); initialConnectionTcs = new TaskCompletionSource(); reconnectTaskLock = new object(); @@ -159,7 +157,7 @@ public async ValueTask - public async Task NextMessage(CancellationToken cancellationToken) + public async Task NextMessage(CancellationToken cancellationToken) { while (true) { @@ -193,15 +191,15 @@ public Task SetReconnectInterval(uint reconnectInterval, bool connectNow) } /// - public abstract ValueTask SendMessage(Message replyTo, MessageContent message, ulong channelId, CancellationToken cancellationToken); + public abstract ValueTask SendMessage(Message? replyTo, MessageContent message, ulong channelId, CancellationToken cancellationToken); /// public abstract ValueTask>>> SendUpdateMessage( RevisionInformation revisionInformation, Api.Models.EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, - string gitHubOwner, - string gitHubRepo, + string? gitHubOwner, + string? gitHubRepo, ulong channelId, bool localCommitPushed, CancellationToken cancellationToken); @@ -234,7 +232,7 @@ protected abstract ValueTask for . ///

/// The to queue. A value of indicates the channel mappings are out of date. - protected void EnqueueMessage(Message message) + protected void EnqueueMessage(Message? message) { if (message == null) Logger.LogTrace("Requesting channel remap..."); @@ -259,7 +257,7 @@ Task StopReconnectionTimer() reconnectCts.Cancel(); reconnectCts.Dispose(); reconnectCts = null; - var reconnectTask = this.reconnectTask; + var reconnectTask = this.reconnectTask!; this.reconnectTask = null; return reconnectTask; } From 85207f6ce8f741bcd6b523865497b44f52537c05 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 21:59:06 -0500 Subject: [PATCH 489/717] Nullify `ProviderFactory` --- .../Components/Chat/Providers/ProviderFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs index 9519abcc1c2..ed3608b92da 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Providers { /// From de1872cd7f4cf1b69cb05ef11519b49f4bf704bf Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 17 Dec 2023 22:22:23 -0500 Subject: [PATCH 490/717] Nullify `ChatManager` --- .../Components/Chat/ChatManager.cs | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index 44e6625691b..b6000a7619c 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -21,8 +21,6 @@ using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat { /// @@ -103,17 +101,17 @@ sealed class ChatManager : IChatManager, IRestartHandler /// /// The for the . /// - ICustomCommandHandler customCommandHandler; + ICustomCommandHandler? customCommandHandler; /// /// The that monitors incoming chat messages. /// - Task chatHandler; + Task? chatHandler; /// /// A that represents the s initial connection. /// - Task initialProviderConnectionsTask; + Task? initialProviderConnectionsTask; /// /// A that represents all sent messages. @@ -256,7 +254,7 @@ public async ValueTask ChangeChannels(long connectionId, IEnumerable x.Id); + var newSettingsEnabled = Models.ModelExtensions.Require(newSettings, x => x.Enabled); lock (providers) { // raw settings changes forces a rebuild of the provider - if (providers.ContainsKey(newSettings.Id.Value)) - disconnectTask = DeleteConnection(newSettings.Id.Value, cancellationToken); + if (providers.ContainsKey(newSettingsId)) + disconnectTask = DeleteConnection(newSettingsId, cancellationToken); else disconnectTask = Task.CompletedTask; - if (newSettings.Enabled.Value) + if (newSettingsEnabled) { provider = providerFactory.CreateProvider(newSettings); - providers.Add(newSettings.Id.Value, provider); + providers.Add(newSettingsId, provider); } } lock (mappedChannels) - foreach (var oldMappedChannelId in mappedChannels.Where(x => x.Value.ProviderId == newSettings.Id).Select(x => x.Key).ToList()) + foreach (var oldMappedChannelId in mappedChannels.Where(x => x.Value.ProviderId == newSettingsId).Select(x => x.Key).ToList()) mappedChannels.Remove(oldMappedChannelId); await disconnectTask; @@ -318,8 +318,8 @@ public async ValueTask ChangeSettings(Models.ChatBot newSettings, CancellationTo } var reconnectionUpdateTask = provider?.SetReconnectInterval( - newSettings.ReconnectionInterval.Value, - newSettings.Enabled.Value) + Models.ModelExtensions.Require(newSettings, x => x.ReconnectionInterval), + newSettingsEnabled) ?? Task.CompletedTask; lock (activeChatBots) { @@ -358,7 +358,7 @@ public void QueueWatchdogMessage(string message) message = String.Format(CultureInfo.InvariantCulture, "WD: {0}", message); - if (!initialProviderConnectionsTask.IsCompleted) + if (!initialProviderConnectionsTask!.IsCompleted) logger.LogTrace("Waiting for initial provider connections before sending watchdog message..."); // Reimplementing QueueMessage @@ -397,11 +397,11 @@ public Func> QueueDeploymentMessage( wdChannels.Select( async x => { - ChannelMapping channelMapping; + ChannelMapping? channelMapping; lock (mappedChannels) if (!mappedChannels.TryGetValue(x, out channelMapping)) return; - IProvider provider; + IProvider? provider; lock (providers) if (!providers.TryGetValue(channelMapping.ProviderId, out provider)) return; @@ -432,7 +432,7 @@ public Func> QueueDeploymentMessage( AddMessageTask(task); Task callbackTask; - Func finalUpdateAction = null; + Func? finalUpdateAction = null; async Task CallbackTask(string errorMessage, string dreamMakerOutput) { await task; @@ -458,7 +458,7 @@ async Task CompletionTask(bool active) return; } - AddMessageTask(finalUpdateAction(active)); + AddMessageTask(finalUpdateAction!(active)); } return (errorMessage, dreamMakerOutput) => @@ -496,7 +496,7 @@ public IChatTrackingContext CreateTrackingContext() if (customCommandHandler == null) throw new InvalidOperationException("RegisterCommandHandler() hasn't been called!"); - IChatTrackingContext context = null; + IChatTrackingContext context = null!; lock (mappedChannels) context = new ChatTrackingContext( customCommandHandler, @@ -525,7 +525,7 @@ async Task UpdateTrackingContext(IChatTrackingContext channelSink, IEnumerable - public ValueTask HandleRestart(Version updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken) + public ValueTask HandleRestart(Version? updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken) { var message = updateVersion == null ? $"TGS: {(handlerMayDelayShutdownWithExtremelyLongRunningTasks ? "Graceful shutdown" : "Going down")}..." @@ -619,10 +619,10 @@ public ValueTask HandleRestart(Version updateVersion, bool handlerMayDelayShutdo /// If the provider should be removed from and should be update. /// The for the operation. /// A resulting in the being removed if it exists, otherwise. - async ValueTask RemoveProviderChannels(long connectionId, bool removeProvider, CancellationToken cancellationToken) + async ValueTask RemoveProviderChannels(long connectionId, bool removeProvider, CancellationToken cancellationToken) { logger.LogTrace("RemoveProviderChannels {connectionId}...", connectionId); - IProvider provider; + IProvider? provider; lock (providers) { if (!providers.TryGetValue(connectionId, out provider)) @@ -664,7 +664,7 @@ async ValueTask RemoveProviderChannels(long connectionId, bool remove async ValueTask RemapProvider(IProvider provider, CancellationToken cancellationToken) { logger.LogTrace("Remapping channels for provider reconnection..."); - IEnumerable channelsToMap; + IEnumerable? channelsToMap; long providerId; lock (providers) providerId = providers.Where(x => x.Value == provider).Select(x => x.Key).First(); @@ -685,7 +685,7 @@ async ValueTask RemapProvider(IProvider provider, CancellationToken cancellation /// The for the operation. /// A representing the running operation. #pragma warning disable CA1502 - async ValueTask ProcessMessage(IProvider provider, Message message, bool recursed, CancellationToken cancellationToken) + async ValueTask ProcessMessage(IProvider provider, Message? message, bool recursed, CancellationToken cancellationToken) #pragma warning restore CA1502 { if (!provider.Connected) @@ -843,16 +843,16 @@ ValueTask TextReply(string reply) => SendMessage( splits.RemoveAt(0); var arguments = String.Join(" ", splits); - Tuple GetCommand() + Tuple? GetCommand() { if (!builtinCommands.TryGetValue(command, out var handler)) return trackingContexts .Where(trackingContext => trackingContext.Active) - .SelectMany(trackingContext => trackingContext.CustomCommands.Select(customCommand => Tuple.Create(customCommand, trackingContext))) + .SelectMany(trackingContext => trackingContext.CustomCommands.Select(customCommand => Tuple.Create(customCommand, trackingContext))) .Where(tuple => tuple.Item1.Name.Equals(command, StringComparison.OrdinalIgnoreCase)) .FirstOrDefault(); - return Tuple.Create(handler, null); + return Tuple.Create(handler, null); } const string UnknownCommandMessage = "TGS: Unknown command! Type '?' or 'help' for available commands."; @@ -935,11 +935,11 @@ Tuple GetCommand() async Task MonitorMessages(CancellationToken cancellationToken) { logger.LogTrace("Starting processing loop..."); - var messageTasks = new Dictionary>(); + var messageTasks = new Dictionary>(); ValueTask activeProcessingTask = ValueTask.CompletedTask; try { - Task updatedTask = null; + Task? updatedTask = null; while (!cancellationToken.IsCancellationRequested) { if (updatedTask?.IsCompleted != false) @@ -1025,7 +1025,7 @@ async ValueTask WrapProcessMessage() /// The to send. /// The for the operation. /// A representing the running operation. - ValueTask SendMessage(IEnumerable channelIds, Message replyTo, MessageContent message, CancellationToken cancellationToken) + ValueTask SendMessage(IEnumerable channelIds, Message? replyTo, MessageContent message, CancellationToken cancellationToken) { var channelIdsList = channelIds.ToList(); @@ -1041,11 +1041,11 @@ ValueTask SendMessage(IEnumerable channelIds, Message replyTo, MessageCon return ValueTaskExtensions.WhenAll( channelIdsList.Select(x => { - ChannelMapping channelMapping; + ChannelMapping? channelMapping; lock (mappedChannels) if (!mappedChannels.TryGetValue(x, out channelMapping)) return ValueTask.CompletedTask; - IProvider provider; + IProvider? provider; lock (providers) if (!providers.TryGetValue(channelMapping.ProviderId, out provider)) return ValueTask.CompletedTask; @@ -1102,7 +1102,7 @@ async Task SendMessageTask() { var cancellationToken = handlerCts.Token; if (waitForConnections) - await initialProviderConnectionsTask.WaitAsync(cancellationToken); + await initialProviderConnectionsTask!.WaitAsync(cancellationToken); await SendMessage( channelIdsFactory(), From 8ee927486e8f45565eb950440b1b9b248c352627 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 13:21:59 -0500 Subject: [PATCH 491/717] Nullify `DiscordProvider` Also partially fixes case of non-github owner/names --- .../Chat/Providers/DiscordProvider.cs | 96 ++++++++++--------- 1 file changed, 53 insertions(+), 43 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 3a89c2245c1..958aa54b261 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -33,8 +33,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Providers { /// @@ -106,17 +104,17 @@ public override string BotMention /// /// The for the . /// - CancellationTokenSource gatewayCts; + CancellationTokenSource? gatewayCts; /// /// The for the initial gateway connection event. /// - TaskCompletionSource gatewayReadyTcs; + TaskCompletionSource? gatewayReadyTcs; /// /// The representing the lifetime of the client. /// - Task gatewayTask; + Task? gatewayTask; /// /// The bot's . @@ -159,8 +157,8 @@ public DiscordProvider( mappedChannels = new List(); connectDisconnectLock = new object(); - var csb = new DiscordConnectionStringBuilder(chatBot.ConnectionString); - var botToken = csb.BotToken; + var csb = new DiscordConnectionStringBuilder(chatBot.ConnectionString!); + var botToken = csb.BotToken!; outputDisplayType = csb.DMOutputDisplay; deploymentBranding = csb.DeploymentBranding; @@ -196,7 +194,7 @@ public override async ValueTask DisposeAsync() } /// - public override async ValueTask SendMessage(Message replyTo, MessageContent message, ulong channelId, CancellationToken cancellationToken) + public override async ValueTask SendMessage(Message? replyTo, MessageContent message, ulong channelId, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(message); @@ -291,21 +289,19 @@ public override async ValueTask author = new EmbedAuthor(assemblyInformationProvider.VersionPrefix) { Url = "https://github.com/tgstation/tgstation-server", IconUrl = "https://cdn.discordapp.com/attachments/1114451486374637629/1151650846019432448/tgs.png", @@ -325,7 +321,7 @@ public override async ValueTask(); - var prefix = GetEngineCompilerPrefix(engineVersion.Engine.Value); + var prefix = GetEngineCompilerPrefix(engineVersion.Engine!.Value); var messageResponse = await channelsClient.CreateMessageAsync( new Snowflake(channelId), $"{prefix}: Deployment in progress...", @@ -388,7 +384,7 @@ public override async ValueTask RespondAsync(IMessageCreate messageCreateEvent, Cancel RealId = messageCreateEvent.Author.ID.Value, Channel = new ChannelRepresentation( pm ? messageCreateEvent.Author.Username : guildName, - channelResponse.Entity.Name.Value, + channelResponse.Entity.Name.Value!, messageCreateEvent.ChannelID.Value) { IsPrivateChannel = pm, @@ -635,8 +631,8 @@ protected override async ValueTask DisconnectImpl(CancellationToken cancellation CancellationTokenSource localGatewayCts; lock (connectDisconnectLock) { - localGatewayTask = gatewayTask; - localGatewayCts = gatewayCts; + localGatewayTask = gatewayTask!; + localGatewayCts = gatewayCts!; gatewayTask = null; gatewayCts = null; if (localGatewayTask == null) @@ -662,7 +658,7 @@ protected override async ValueTask DisconnectImpl(CancellationToken cancellation var guildsClient = serviceProvider.GetRequiredService(); var guildTasks = new ConcurrentDictionary>>(); - async ValueTask>> GetModelChannelFromDBChannel(Models.ChatChannel channelFromDB) + async ValueTask>?> GetModelChannelFromDBChannel(Models.ChatChannel channelFromDB) { if (!channelFromDB.DiscordChannelId.HasValue) throw new InvalidOperationException("ChatChannel missing DiscordChannelId!"); @@ -721,7 +717,7 @@ protected override async ValueTask DisconnectImpl(CancellationToken cancellation var channelModel = new ChannelRepresentation( guildsResponse.Entity.Name, - discordChannelResponse.Entity.Name.Value, + discordChannelResponse.Entity.Name.Value!, channelId) { IsAdminChannel = channelFromDB.IsAdminChannel == true, @@ -742,8 +738,9 @@ protected override async ValueTask DisconnectImpl(CancellationToken cancellation var channelTuples = await ValueTaskExtensions.WhenAll(tasks.ToList()); - var enumerator = channelTuples + var list = channelTuples .Where(x => x != null) + .Cast>>() // NRT my beloathed .ToList(); var channelIdZeroModel = channels.FirstOrDefault(x => x.DiscordChannelId == 0); @@ -752,7 +749,7 @@ protected override async ValueTask DisconnectImpl(CancellationToken cancellation Logger.LogInformation("Mapping ALL additional accessible text channels"); var allAccessibleChannels = await GetAllAccessibleTextChannels(cancellationToken); var unmappedTextChannels = allAccessibleChannels - .Where(x => !tasks.Any(task => task.Result != null && new Snowflake(task.Result.Item1.DiscordChannelId.Value) == x.ID)); + .Where(x => !tasks.Any(task => task.Result != null && new Snowflake(task.Result.Item1.DiscordChannelId!.Value) == x.ID)); async ValueTask>> CreateMappingsForUnmappedChannels() { @@ -773,13 +770,13 @@ protected override async ValueTask DisconnectImpl(CancellationToken cancellation .ToList(); // Add catch-all channel - unmappedTasks.Add(Task.FromResult( + unmappedTasks.Add(Task.FromResult( new ChannelRepresentation( "(Unknown Discord Guilds)", "(Unknown Discord Channels)", 0) { - IsAdminChannel = channelIdZeroModel.IsAdminChannel.Value, + IsAdminChannel = channelIdZeroModel.IsAdminChannel!.Value, EmbedsSupported = true, Tag = channelIdZeroModel.Tag, })); @@ -787,18 +784,22 @@ protected override async ValueTask DisconnectImpl(CancellationToken cancellation await Task.WhenAll(unmappedTasks); return Tuple.Create>( channelIdZeroModel, - unmappedTasks.Select(x => x.Result).Where(x => x != null).ToList()); + unmappedTasks + .Select(x => x.Result) + .Where(x => x != null) + .Cast() // NRT my beloathed + .ToList()); } var task = CreateMappingsForUnmappedChannels(); var tuple = await task; - enumerator.Add(tuple); + list.Add(tuple); } lock (mappedChannels) { mappedChannels.Clear(); - mappedChannels.AddRange(enumerator.SelectMany(x => x.Item2).Select(x => x.RealId)); + mappedChannels.AddRange(list.SelectMany(x => x.Item2).Select(x => x.RealId)); } if (remapRequired) @@ -807,7 +808,7 @@ protected override async ValueTask DisconnectImpl(CancellationToken cancellation EnqueueMessage(null); } - return new Dictionary>(enumerator.Select(x => new KeyValuePair>(x.Item1, x.Item2))); + return new Dictionary>(list.Select(x => new KeyValuePair>(x.Item1, x.Item2))); } /// @@ -881,46 +882,55 @@ async ValueTask> GetGuildChannels(IPartialGuild guild) List BuildUpdateEmbedFields( Models.RevisionInformation revisionInformation, EngineVersion engineVersion, - string gitHubOwner, - string gitHubRepo, + string? gitHubOwner, + string? gitHubRepo, bool localCommitPushed) { bool gitHub = gitHubOwner != null && gitHubRepo != null; - var engineField = engineVersion.Engine.Value switch + var engineField = engineVersion.Engine!.Value switch { EngineType.Byond => new EmbedField( "BYOND Version", - $"{engineVersion.Version.Major}.{engineVersion.Version.Minor}{(engineVersion.CustomIteration.HasValue ? $".{engineVersion.CustomIteration.Value}" : String.Empty)}", + $"{engineVersion.Version!.Major}.{engineVersion.Version.Minor}{(engineVersion.CustomIteration.HasValue ? $".{engineVersion.CustomIteration.Value}" : String.Empty)}", true), EngineType.OpenDream => new EmbedField( "OpenDream Version", - $"[{engineVersion.SourceSHA[..7]}]({generalConfiguration.OpenDreamGitUrl}/commit/{engineVersion.SourceSHA})", + $"[{engineVersion.SourceSHA![..7]}]({generalConfiguration.OpenDreamGitUrl}/commit/{engineVersion.SourceSHA})", true), _ => throw new InvalidOperationException($"Invaild EngineType: {engineVersion.Engine.Value}"), }; + var revisionSha = revisionInformation.CommitSha!; + var revisionOriginSha = revisionInformation.OriginCommitSha!; var fields = new List { engineField, + }; + + if (gitHubOwner == null || gitHubRepo == null) + return fields; + + fields.Add( new EmbedField( "Local Commit", localCommitPushed && gitHub - ? $"[{revisionInformation.CommitSha[..7]}](https://github.com/{gitHubOwner}/{gitHubRepo}/commit/{revisionInformation.CommitSha})" - : revisionInformation.CommitSha[..7], - true), + ? $"[{revisionSha[..7]}](https://github.com/{gitHubOwner}/{gitHubRepo}/commit/{revisionSha})" + : revisionSha[..7], + true)); + + fields.Add( new EmbedField( "Branch Commit", gitHub - ? $"[{revisionInformation.OriginCommitSha[..7]}](https://github.com/{gitHubOwner}/{gitHubRepo}/commit/{revisionInformation.OriginCommitSha})" - : revisionInformation.OriginCommitSha[..7], - true), - }; + ? $"[{revisionOriginSha[..7]}](https://github.com/{gitHubOwner}/{gitHubRepo}/commit/{revisionOriginSha})" + : revisionOriginSha[..7], + true)); fields.AddRange((revisionInformation.ActiveTestMerges ?? Enumerable.Empty()) .Select(x => x.TestMerge) .Select(x => new EmbedField( $"#{x.Number}", - $"[{x.TitleAtMerge}]({x.Url}) by _[@{x.Author}](https://github.com/{x.Author})_{Environment.NewLine}Commit: [{x.TargetCommitSha[..7]}](https://github.com/{gitHubOwner}/{gitHubRepo}/commit/{x.TargetCommitSha}){(String.IsNullOrWhiteSpace(x.Comment) ? String.Empty : $"{Environment.NewLine}_**{x.Comment}**_")}", + $"[{x.TitleAtMerge}]({x.Url}) by _[@{x.Author}](https://github.com/{x.Author})_{Environment.NewLine}Commit: [{x.TargetCommitSha![..7]}](https://github.com/{gitHubOwner}/{gitHubRepo}/commit/{x.TargetCommitSha}){(String.IsNullOrWhiteSpace(x.Comment) ? String.Empty : $"{Environment.NewLine}_**{x.Comment}**_")}", false))); return fields; @@ -955,7 +965,7 @@ Optional> ConvertEmbed(ChatEmbed embed) embed.Author = null; } - List fields = null; + List? fields = null; if (embed.Fields != null) { fields = new List(); @@ -1037,7 +1047,7 @@ Optional> ConvertEmbed(ChatEmbed embed) Description = embed.Description ?? default(Optional), Fields = fields ?? default(Optional>), Footer = embed.Footer != null - ? new EmbedFooter(embed.Footer.Text) + ? (Optional)new EmbedFooter(embed.Footer.Text) { IconUrl = embed.Footer.IconUrl ?? default(Optional), ProxyIconUrl = embed.Footer.ProxyIconUrl ?? default(Optional), From 6d03d2ec57e615d8a743346f5b781e7569088e36 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 13:23:15 -0500 Subject: [PATCH 492/717] Nullify `DiscordForwardingResponder` --- .../Components/Chat/Providers/DiscordForwardingResponder.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordForwardingResponder.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordForwardingResponder.cs index 878ac1bc4c1..85444cb499b 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordForwardingResponder.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordForwardingResponder.cs @@ -6,8 +6,6 @@ using Remora.Discord.Gateway.Responders; using Remora.Results; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Providers { /// From d5d5eabc5aad48ab93f5dd7f6564c7a39bc1513d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 13:44:34 -0500 Subject: [PATCH 493/717] Nullify `IrcProvider` --- .../Components/Chat/Providers/IrcProvider.cs | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index 70665bf6953..5207cc380d8 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -19,8 +19,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat.Providers { /// @@ -77,7 +75,7 @@ sealed class IrcProvider : Provider /// /// Map of s to channel names. /// - readonly Dictionary channelIdMap; + readonly Dictionary channelIdMap; /// /// Map of s to query users. @@ -85,14 +83,14 @@ sealed class IrcProvider : Provider readonly Dictionary queryChannelIdMap; /// - /// Id counter for . + /// The used for . /// - ulong channelIdCounter; + Task? listenTask; /// - /// The used for . + /// Id counter for . /// - Task listenTask; + ulong channelIdCounter; /// /// If we are disconnecting. @@ -121,11 +119,11 @@ public IrcProvider( if (builder == null || !builder.Valid || builder is not IrcConnectionStringBuilder ircBuilder) throw new InvalidOperationException("Invalid ChatConnectionStringBuilder!"); - address = ircBuilder.Address; - port = ircBuilder.Port.Value; - nickname = ircBuilder.Nickname; + address = ircBuilder.Address!; + port = ircBuilder.Port!.Value; + nickname = ircBuilder.Nickname!; - password = ircBuilder.Password; + password = ircBuilder.Password!; passwordType = ircBuilder.PasswordType; client = new IrcFeatures @@ -140,7 +138,7 @@ public IrcProvider( ActiveChannelSyncing = true, AutoNickHandling = true, CtcpVersion = assemblyInformationProvider.VersionString, - UseSsl = ircBuilder.UseSsl.Value, + UseSsl = ircBuilder.UseSsl!.Value, }; if (ircBuilder.UseSsl.Value) client.ValidateServerCertificate = true; // dunno if it defaults to that or what @@ -151,7 +149,7 @@ public IrcProvider( /*client.OnReadLine += (sender, e) => Logger.LogTrace("READ: {line}", e.Line); client.OnWriteLine += (sender, e) => Logger.LogTrace("WRITE: {line}", e.Line);*/ - channelIdMap = new Dictionary(); + channelIdMap = new Dictionary(); queryChannelIdMap = new Dictionary(); channelIdCounter = 1; } @@ -166,7 +164,7 @@ public override async ValueTask DisposeAsync() } /// - public override async ValueTask SendMessage(Message replyTo, MessageContent message, ulong channelId, CancellationToken cancellationToken) + public override async ValueTask SendMessage(Message? replyTo, MessageContent message, ulong channelId, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(message); @@ -224,8 +222,8 @@ public override async ValueTask x.TestMerge) .Select(x => { - var result = String.Format(CultureInfo.InvariantCulture, "#{0} at {1}", x.Number, x.TargetCommitSha[..7]); + var result = String.Format(CultureInfo.InvariantCulture, "#{0} at {1}", x.Number, x.TargetCommitSha![..7]); if (x.Comment != null) result += String.Format(CultureInfo.InvariantCulture, " ({0})", x.Comment); return result; }))); - var prefix = GetEngineCompilerPrefix(engineVersion.Engine.Value); + var prefix = GetEngineCompilerPrefix(engineVersion.Engine!.Value); await SendMessage( null, new MessageContent @@ -353,7 +351,7 @@ await SendMessage( dbChannel, new List { - new(address, channelIdMap[id.Value], id.Value) + new(address, channelName, id!.Value) { Tag = dbChannel.Tag, IsAdminChannel = dbChannel.IsAdminChannel == true, @@ -502,7 +500,7 @@ void HandleMessage(IrcEventArgs e, bool isPrivate) var username = e.Data.Nick; var channelName = isPrivate ? username : e.Data.Channel; - ulong MapAndGetChannelId(Dictionary dicToCheck) + ulong MapAndGetChannelId(Dictionary dicToCheck) { ulong? resultId = null; if (!dicToCheck.Any(x => @@ -519,13 +517,14 @@ ulong MapAndGetChannelId(Dictionary dicToCheck) channelIdMap.Add(resultId.Value, null); } - return resultId.Value; + return resultId!.Value; } ulong userId, channelId; lock (client) { - userId = MapAndGetChannelId(queryChannelIdMap); + userId = MapAndGetChannelId(new Dictionary(queryChannelIdMap + .Cast>())); // NRT my beloathed channelId = isPrivate ? userId : MapAndGetChannelId(channelIdMap); } From bd80c592babdf26a028140a8ed9366a24bcc2f2a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 13:51:28 -0500 Subject: [PATCH 494/717] Update to `Byond.TopicSender` v8.0.1 --- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index b9b2690ae26..6bb958fb744 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -64,7 +64,7 @@ - + From 9ab553fe175d6e0fcfdf6a7e57681864f36dd730 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:07:48 -0500 Subject: [PATCH 495/717] Nullify `BufferedFileStreamProvider` --- src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs b/src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs index e4a8fcd139b..d1310029df3 100644 --- a/src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs +++ b/src/Tgstation.Server.Host/IO/BufferedFileStreamProvider.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.IO { /// @@ -30,7 +28,7 @@ public sealed class BufferedFileStreamProvider : ISeekableFileStreamProvider /// /// The backing . /// - volatile MemoryStream buffer; + volatile MemoryStream? buffer; /// /// If has been populated. @@ -60,7 +58,7 @@ public BufferedFileStreamProvider(Stream input) /// public async ValueTask DisposeAsync() { - MemoryStream localBuffer; + MemoryStream? localBuffer; lock (semaphore) { localBuffer = buffer; From 49809d690cd422d22cba6ca13dd08cf2114bb51d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:13:51 -0500 Subject: [PATCH 496/717] Nullify `IConsole` and `Console` --- .../Components/InstanceManager.cs | 4 ++-- src/Tgstation.Server.Host/IO/Console.cs | 24 ++++++++++--------- src/Tgstation.Server.Host/IO/IConsole.cs | 12 ++++++---- .../Setup/SetupWizard.cs | 4 ++-- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index af7a3d7c814..50da066c525 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -489,7 +489,7 @@ async ValueTask OfflineInstanceImmediate(IInstance instance, CancellationToken c finally { if (originalConsoleTitle != null) - console.Title = originalConsoleTitle; + console.SetTitle(originalConsoleTitle); } } catch (Exception ex) @@ -569,7 +569,7 @@ async Task Initialize(CancellationToken cancellationToken) try { logger.LogInformation("{versionString}", assemblyInformationProvider.VersionString); - console.Title = assemblyInformationProvider.VersionString; + console.SetTitle(assemblyInformationProvider.VersionString); CheckSystemCompatibility(); diff --git a/src/Tgstation.Server.Host/IO/Console.cs b/src/Tgstation.Server.Host/IO/Console.cs index ae6efa4ed7f..6a94540bb0b 100644 --- a/src/Tgstation.Server.Host/IO/Console.cs +++ b/src/Tgstation.Server.Host/IO/Console.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.IO { /// @@ -15,13 +13,9 @@ namespace Tgstation.Server.Host.IO sealed class Console : IConsole, IDisposable { /// - public string Title - { - get => platformIdentifier.IsWindows - ? global::System.Console.Title - : null; - set => global::System.Console.Title = value; - } + public string? Title => platformIdentifier.IsWindows + ? global::System.Console.Title + : null; /// public bool Available => Environment.UserInteractive; @@ -91,7 +85,8 @@ public Task ReadLineAsync(bool usePasswordChar, CancellationToken cancel // TODO: Make this better: https://stackoverflow.com/questions/9479573/how-to-interrupt-console-readline CheckAvailable(); if (!usePasswordChar) - return global::System.Console.ReadLine(); + return global::System.Console.ReadLine() + ?? throw new InvalidOperationException("Console input has been closed!"); var passwordBuilder = new StringBuilder(); do @@ -126,7 +121,7 @@ public Task ReadLineAsync(bool usePasswordChar, CancellationToken cancel .WaitAsync(cancellationToken); /// - public Task WriteAsync(string text, bool newLine, CancellationToken cancellationToken) => Task.Factory.StartNew( + public Task WriteAsync(string? text, bool newLine, CancellationToken cancellationToken) => Task.Factory.StartNew( () => { CheckAvailable(); @@ -145,6 +140,13 @@ public Task WriteAsync(string text, bool newLine, CancellationToken cancellation DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current); + /// + public void SetTitle(string newTitle) + { + ArgumentNullException.ThrowIfNull(newTitle); + global::System.Console.Title = newTitle; + } + /// /// Assert that the is available, throwing an otherwise. /// diff --git a/src/Tgstation.Server.Host/IO/IConsole.cs b/src/Tgstation.Server.Host/IO/IConsole.cs index cc71295c554..ee1e9488917 100644 --- a/src/Tgstation.Server.Host/IO/IConsole.cs +++ b/src/Tgstation.Server.Host/IO/IConsole.cs @@ -1,8 +1,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.IO { /// @@ -13,7 +11,7 @@ interface IConsole /// /// Gets or sets the window's title. Can return if getting the console title is not supported. /// - string Title { get; set; } + string? Title { get; } /// /// If the is visible to the user. @@ -32,7 +30,7 @@ interface IConsole /// If there should be a new line after the . /// The for the operation. /// A representing the running operation. - Task WriteAsync(string text, bool newLine, CancellationToken cancellationToken); + Task WriteAsync(string? text, bool newLine, CancellationToken cancellationToken); /// /// Wait for a key press on the . @@ -48,5 +46,11 @@ interface IConsole /// The for the operation. /// A resulting in the read by the . Task ReadLineAsync(bool usePasswordChar, CancellationToken cancellationToken); + + /// + /// Sets a console window. + /// + /// The new . + void SetTitle(string newTitle); } } diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index ba82f4bc182..c8007f16b50 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -1107,7 +1107,7 @@ void SetConsoleTitle() return; originalConsoleTitle = console.Title; - console.Title = $"{assemblyInformationProvider.VersionString} Setup Wizard"; + console.SetTitle($"{assemblyInformationProvider.VersionString} Setup Wizard"); } // Link passed cancellationToken with cancel key press @@ -1197,7 +1197,7 @@ await SaveConfiguration( { await finalTask; if (originalConsoleTitle != null) - console.Title = originalConsoleTitle; + console.SetTitle(originalConsoleTitle); } } } From ca94ce577e0efa937d3430bec841c5fb592cf9e5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:18:01 -0500 Subject: [PATCH 497/717] Nullify `IIOManager` --- .../Configuration/InternalConfiguration.cs | 2 +- src/Tgstation.Server.Host/IO/IIOManager.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs b/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs index 832041debac..58f2ad4720b 100644 --- a/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/InternalConfiguration.cs @@ -28,7 +28,7 @@ public sealed class InternalConfiguration /// /// The base path for the app settings configuration files. /// - public string? AppSettingsBasePath { get; set; } + public string AppSettingsBasePath { get; set; } = "UNINITIALIZED"; // this is set in a hacky way in ServerFactory /// /// Coerce the to select . diff --git a/src/Tgstation.Server.Host/IO/IIOManager.cs b/src/Tgstation.Server.Host/IO/IIOManager.cs index b66bd6f0fab..ec43f1d23f7 100644 --- a/src/Tgstation.Server.Host/IO/IIOManager.cs +++ b/src/Tgstation.Server.Host/IO/IIOManager.cs @@ -4,8 +4,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.IO { /// @@ -59,7 +57,7 @@ public interface IIOManager /// A representing the running operation. ValueTask CopyDirectory( IEnumerable ignore, - Func postCopyCallback, + Func? postCopyCallback, string src, string dest, int? taskThrottle, From 16ed57cbb532416c75e573c1259ed8e6bd638a3a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:19:19 -0500 Subject: [PATCH 498/717] Nullify `DefaultIOManager` --- .../IO/DefaultIOManager.cs | 17 ++++++++--------- src/Tgstation.Server.Host/IO/IIOManager.cs | 1 + .../System/ProcessExecutor.cs | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs index 321271faf94..89231a6a49d 100644 --- a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs +++ b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs @@ -8,8 +8,6 @@ using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.IO { /// @@ -72,7 +70,7 @@ static void NormalizeAndDelete(DirectoryInfo dir, CancellationToken cancellation /// public async ValueTask CopyDirectory( IEnumerable ignore, - Func postCopyCallback, + Func? postCopyCallback, string src, string dest, int? taskThrottle, @@ -142,7 +140,8 @@ public Task DeleteDirectory(string path, CancellationToken cancellationToken) public Task DirectoryExists(string path, CancellationToken cancellationToken) => Task.Factory.StartNew(() => Directory.Exists(ResolvePath(path)), cancellationToken, BlockingTaskCreationOptions, TaskScheduler.Current); /// - public string GetDirectoryName(string path) => Path.GetDirectoryName(path ?? throw new ArgumentNullException(nameof(path))); + public string GetDirectoryName(string path) => Path.GetDirectoryName(path ?? throw new ArgumentNullException(nameof(path))) + ?? throw new InvalidOperationException($"Null was returned. Path ({path}) must be rooted. This is not supported!"); /// public string GetFileName(string path) => Path.GetFileName(path ?? throw new ArgumentNullException(nameof(path))); @@ -338,7 +337,7 @@ public Task GetLastModified(string path, CancellationToken cance /// /// The source directory path. /// The destination directory path. - /// Files and folders to ignore at the root level. + /// Optional files and folders to ignore at the root level. /// The optional callback called for each source/dest file pair post copy. /// Optional used to limit degree of parallelism. /// The for the operation. @@ -346,13 +345,13 @@ public Task GetLastModified(string path, CancellationToken cance IEnumerable CopyDirectoryImpl( string src, string dest, - IEnumerable ignore, - Func postCopyCallback, - SemaphoreSlim semaphore, + IEnumerable? ignore, + Func? postCopyCallback, + SemaphoreSlim? semaphore, CancellationToken cancellationToken) { var dir = new DirectoryInfo(src); - Task subdirCreationTask = null; + Task? subdirCreationTask = null; foreach (var subDirectory in dir.EnumerateDirectories()) { if (ignore != null && ignore.Contains(subDirectory.Name)) diff --git a/src/Tgstation.Server.Host/IO/IIOManager.cs b/src/Tgstation.Server.Host/IO/IIOManager.cs index ec43f1d23f7..ed4a90fb526 100644 --- a/src/Tgstation.Server.Host/IO/IIOManager.cs +++ b/src/Tgstation.Server.Host/IO/IIOManager.cs @@ -133,6 +133,7 @@ ValueTask CopyDirectory( /// /// A path to check. /// The directory portion of the given . + /// If is rooted. string GetDirectoryName(string path); /// diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs index a0a787e53b4..7820ca11b39 100644 --- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs +++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs @@ -229,7 +229,7 @@ public IProcess LaunchProcess( handle.StartInfo.RedirectStandardError = true; bool writingToFile; - await using var fileStream = (writingToFile = fileRedirect != null) ? ioManager.CreateAsyncSequentialWriteStream(fileRedirect) : null; + await using var fileStream = (writingToFile = fileRedirect != null) ? ioManager.CreateAsyncSequentialWriteStream(fileRedirect!) : null; await using var fileWriter = fileStream != null ? new StreamWriter(fileStream) : null; var stringBuilder = fileStream == null ? new StringBuilder() : null; From ef2fca7b4d0c47a66b8e3fea85c6a5ae9f923763 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:22:09 -0500 Subject: [PATCH 499/717] Nullify `IFileDownloader` --- src/Tgstation.Server.Host/IO/IFileDownloader.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/IFileDownloader.cs b/src/Tgstation.Server.Host/IO/IFileDownloader.cs index 6cc9baad869..446700e55f2 100644 --- a/src/Tgstation.Server.Host/IO/IFileDownloader.cs +++ b/src/Tgstation.Server.Host/IO/IFileDownloader.cs @@ -1,7 +1,5 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.IO { /// @@ -15,6 +13,6 @@ interface IFileDownloader /// The URL to download. /// Optional to use as the "Bearer" value in the optional "Authorization" header for the request. /// A new for the downloaded file. - IFileStreamProvider DownloadFile(Uri url, string bearerToken); + IFileStreamProvider DownloadFile(Uri url, string? bearerToken); } } From 671cbfcb934bc2a36d59d5a8bc4bcc86233f26ff Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:22:56 -0500 Subject: [PATCH 500/717] Nullify `FileDownloader` --- src/Tgstation.Server.Host/IO/FileDownloader.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/FileDownloader.cs b/src/Tgstation.Server.Host/IO/FileDownloader.cs index 1b133e9647c..30efdb6718d 100644 --- a/src/Tgstation.Server.Host/IO/FileDownloader.cs +++ b/src/Tgstation.Server.Host/IO/FileDownloader.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Api; using Tgstation.Server.Common.Http; -#nullable disable - namespace Tgstation.Server.Host.IO { /// @@ -36,7 +34,7 @@ public FileDownloader(IAbstractHttpClientFactory httpClientFactory, ILogger - public IFileStreamProvider DownloadFile(Uri url, string bearerToken) + public IFileStreamProvider DownloadFile(Uri url, string? bearerToken) { ArgumentNullException.ThrowIfNull(url); From 0bae4338bb1666d293ad80631e29a00a89ff4025 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:32:01 -0500 Subject: [PATCH 501/717] Nullify `IFilesystemLinkFactory` --- src/Tgstation.Server.Host/IO/IFilesystemLinkFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/IFilesystemLinkFactory.cs b/src/Tgstation.Server.Host/IO/IFilesystemLinkFactory.cs index 36ea58a9dfa..3cf0622801a 100644 --- a/src/Tgstation.Server.Host/IO/IFilesystemLinkFactory.cs +++ b/src/Tgstation.Server.Host/IO/IFilesystemLinkFactory.cs @@ -1,8 +1,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.IO { /// From 645377f469bfef6db02dba2aba91518c65ccd36a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:31:28 -0500 Subject: [PATCH 502/717] Nullify `IFileStreamProvider` and revisit `IFileUploadTicket` Only the latter can have a nullable return value. --- .../IO/IFileStreamProvider.cs | 4 +--- .../Transfer/FileUploadProvider.cs | 21 ++++++++++++------- .../Transfer/IFileUploadTicket.cs | 14 ++++++++++++- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/IFileStreamProvider.cs b/src/Tgstation.Server.Host/IO/IFileStreamProvider.cs index 47a2caca10a..6b1670194d0 100644 --- a/src/Tgstation.Server.Host/IO/IFileStreamProvider.cs +++ b/src/Tgstation.Server.Host/IO/IFileStreamProvider.cs @@ -3,8 +3,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.IO { /// @@ -16,7 +14,7 @@ public interface IFileStreamProvider : IAsyncDisposable /// Gets the provided . May be called multiple times, though cancelling any may cause all calls to be cancelled. All calls yield the same reference. /// /// The for the operation. - /// A resulting in the provided on success, if it could not be provided. + /// A resulting in the provided . /// The resulting is owned by the and is short lived unless otherwise specified. It should be buffered if it needs use outside the lifetime of the . ValueTask GetResult(CancellationToken cancellationToken); } diff --git a/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs b/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs index 23b37788fc6..0dd709dcc85 100644 --- a/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs +++ b/src/Tgstation.Server.Host/Transfer/FileUploadProvider.cs @@ -65,14 +65,6 @@ public ValueTask DisposeAsync() return ValueTask.CompletedTask; } - /// - public async ValueTask GetResult(CancellationToken cancellationToken) - { - using (cancellationToken.Register(() => streamTcs.TrySetCanceled(cancellationToken))) - using (ticketExpiryCts.Token.Register(() => streamTcs.TrySetResult(null))) - return await streamTcs.Task; - } - /// /// Expire the . /// @@ -142,5 +134,18 @@ public void SetError(ErrorCode errorCode, string? additionalData) }; completionTcs.TrySetResult(); } + + /// + public async ValueTask GetResult(CancellationToken cancellationToken) + => await ((IFileUploadTicket)this).GetResult(cancellationToken) + ?? throw new InvalidOperationException("Upload ticket expired!"); + + /// + async ValueTask IFileUploadTicket.GetResult(CancellationToken cancellationToken) + { + using (cancellationToken.Register(() => streamTcs.TrySetCanceled(cancellationToken))) + using (ticketExpiryCts.Token.Register(() => streamTcs.TrySetResult(null))) + return await streamTcs.Task; + } } } diff --git a/src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs b/src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs index 43130810d37..7e1eabf813a 100644 --- a/src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs +++ b/src/Tgstation.Server.Host/Transfer/IFileUploadTicket.cs @@ -1,4 +1,8 @@ -using Tgstation.Server.Api.Models; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Host.IO; @@ -20,5 +24,13 @@ public interface IFileUploadTicket : IFileStreamProvider /// The to set. /// Any additional information that can be provided about the error. void SetError(ErrorCode errorCode, string? additionalData); + + /// + /// Gets the provided . May be called multiple times, though cancelling any may cause all calls to be cancelled. All calls yield the same reference. + /// + /// The for the operation. + /// A resulting in the provided on success, if the upload expired. + /// The resulting is owned by the and is short lived unless otherwise specified. It should be buffered if it needs use outside the lifetime of the . + new ValueTask GetResult(CancellationToken cancellationToken); } } From 4511f1a60c0e7c00652658419249ab3595ddc320 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:48:05 -0500 Subject: [PATCH 503/717] Nullify `ISeekableFileStreamProvider` --- src/Tgstation.Server.Host/IO/ISeekableFileStreamProvider.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/ISeekableFileStreamProvider.cs b/src/Tgstation.Server.Host/IO/ISeekableFileStreamProvider.cs index f34e28745d1..42cfc869534 100644 --- a/src/Tgstation.Server.Host/IO/ISeekableFileStreamProvider.cs +++ b/src/Tgstation.Server.Host/IO/ISeekableFileStreamProvider.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.IO { /// @@ -20,7 +18,7 @@ public interface ISeekableFileStreamProvider : IFileStreamProvider /// Gets the provided . May be called multiple times, though cancelling any may cause all calls to be cancelled. /// /// The for the operation. - /// A resulting in the provided on success, if it could not be provided. + /// A resulting in the provided on success. ValueTask GetOwnedResult(CancellationToken cancellationToken); } } From 1f5834dd7cc6618f9943ac1afa8696fc005e9b0c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:49:11 -0500 Subject: [PATCH 504/717] Remove an unused parameter --- .../Components/Engine/ByondInstallerBase.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index 082eeaf349d..7aef964b9c0 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -200,7 +200,7 @@ public override async ValueTask DownloadVersion(EngineV { CheckVersionValidity(version); - var url = await GetDownloadZipUrl(version, cancellationToken); + var url = GetDownloadZipUrl(version); Logger.LogTrace("Downloading {engineType} version {version} from {url}...", TargetEngineType, version, url); await using var download = fileDownloader.DownloadFile(url, null); @@ -233,13 +233,12 @@ public override async ValueTask DownloadVersion(EngineV /// Create a pointing to the location of the download for a given . /// /// The to create a for. - /// The for the operation. - /// A resulting in a new pointing to the version download location. - ValueTask GetDownloadZipUrl(EngineVersion version, CancellationToken cancellationToken) + /// A pointing to the version download location. + Uri GetDownloadZipUrl(EngineVersion version) { CheckVersionValidity(version); var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Version.Major, version.Version.Minor); - return ValueTask.FromResult(new Uri(url)); + return new Uri(url); } } } From c262f09bd595255ccc7a29efd317e5c69a525194 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:49:25 -0500 Subject: [PATCH 505/717] Nullify `PosixFilesystemLinkFactory` --- src/Tgstation.Server.Host/IO/PosixFilesystemLinkFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/PosixFilesystemLinkFactory.cs b/src/Tgstation.Server.Host/IO/PosixFilesystemLinkFactory.cs index b5355d9aad7..b80af9e122a 100644 --- a/src/Tgstation.Server.Host/IO/PosixFilesystemLinkFactory.cs +++ b/src/Tgstation.Server.Host/IO/PosixFilesystemLinkFactory.cs @@ -5,8 +5,6 @@ using Mono.Unix; -#nullable disable - namespace Tgstation.Server.Host.IO { /// From 9ff89df72086dc4814fa989665dcd931e9330017 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:49:43 -0500 Subject: [PATCH 506/717] Nullify `PosixPostWriteHandler` --- src/Tgstation.Server.Host/IO/PosixPostWriteHandler.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/PosixPostWriteHandler.cs b/src/Tgstation.Server.Host/IO/PosixPostWriteHandler.cs index ec441813b17..a0f4f5a4c8a 100644 --- a/src/Tgstation.Server.Host/IO/PosixPostWriteHandler.cs +++ b/src/Tgstation.Server.Host/IO/PosixPostWriteHandler.cs @@ -4,8 +4,6 @@ using Mono.Unix; using Mono.Unix.Native; -#nullable disable - namespace Tgstation.Server.Host.IO { /// From 1b263ca750fc1af6959386edd1633f4b3e8d5a60 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:50:29 -0500 Subject: [PATCH 507/717] Nullify `RequestFileStreamProvider` --- src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs b/src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs index ef4ddb0d145..12461e4e7f3 100644 --- a/src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs +++ b/src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Common.Http; -#nullable disable - namespace Tgstation.Server.Host.IO { /// @@ -33,7 +31,7 @@ sealed class RequestFileStreamProvider : IFileStreamProvider /// /// The resulting in the downloaded . /// - Task downloadTask; + Task? downloadTask; /// /// If has been called. @@ -56,7 +54,7 @@ public RequestFileStreamProvider(IHttpClient httpClient, HttpRequestMessage requ /// public async ValueTask DisposeAsync() { - Task localDownloadTask; + Task? localDownloadTask; lock (downloadCts) { if (disposed) From 72ff717ec87457c07a042438224d593bc1d6bf58 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:50:43 -0500 Subject: [PATCH 508/717] Nullify `ResolvingIOManager` --- src/Tgstation.Server.Host/IO/ResolvingIOManager.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/ResolvingIOManager.cs b/src/Tgstation.Server.Host/IO/ResolvingIOManager.cs index 665a5b6bc4a..3b86b92c36a 100644 --- a/src/Tgstation.Server.Host/IO/ResolvingIOManager.cs +++ b/src/Tgstation.Server.Host/IO/ResolvingIOManager.cs @@ -1,8 +1,6 @@ using System; using System.IO; -#nullable disable - namespace Tgstation.Server.Host.IO { /// From bd2b6b5d5f823f6e1490da1574ee43e339535830 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:48:32 -0500 Subject: [PATCH 509/717] Nullify `ISynchronousIOManager` --- src/Tgstation.Server.Host/IO/ISynchronousIOManager.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/ISynchronousIOManager.cs b/src/Tgstation.Server.Host/IO/ISynchronousIOManager.cs index df87b894c6f..16e0ea370e8 100644 --- a/src/Tgstation.Server.Host/IO/ISynchronousIOManager.cs +++ b/src/Tgstation.Server.Host/IO/ISynchronousIOManager.cs @@ -2,8 +2,6 @@ using System.IO; using System.Threading; -#nullable disable - namespace Tgstation.Server.Host.IO { /// @@ -57,7 +55,7 @@ interface ISynchronousIOManager /// The function only succeeds if this parameter matches the SHA-1 hash of the contents of the current file. Contains the SHA1 of the file on disk once the function returns. /// The for the operation. /// on success, if the operation failed due to not matching the file's contents. - bool WriteFileChecked(string path, Stream data, ref string sha1InOut, CancellationToken cancellationToken); + bool WriteFileChecked(string path, Stream data, ref string? sha1InOut, CancellationToken cancellationToken); /// /// Checks if a given is a directory. From ac357e935ad7b4df26af9d1ff663a81c778667a7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:52:56 -0500 Subject: [PATCH 510/717] Nullify `SynchronousIOManager` --- src/Tgstation.Server.Host/IO/SynchronousIOManager.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/SynchronousIOManager.cs b/src/Tgstation.Server.Host/IO/SynchronousIOManager.cs index 590cbfbb6fe..4dbf3d833bf 100644 --- a/src/Tgstation.Server.Host/IO/SynchronousIOManager.cs +++ b/src/Tgstation.Server.Host/IO/SynchronousIOManager.cs @@ -6,8 +6,6 @@ using System.Security.Cryptography; using System.Threading; -#nullable disable - namespace Tgstation.Server.Host.IO { /// @@ -74,14 +72,13 @@ public byte[] ReadFile(string path) } /// - public bool WriteFileChecked(string path, Stream data, ref string sha1InOut, CancellationToken cancellationToken) + public bool WriteFileChecked(string path, Stream data, ref string? sha1InOut, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(path); ArgumentNullException.ThrowIfNull(data); cancellationToken.ThrowIfCancellationRequested(); - var directory = Path.GetDirectoryName(path); - + var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException("path cannot be rooted!", nameof(path)); Directory.CreateDirectory(directory); var newFile = !File.Exists(path); @@ -99,7 +96,7 @@ public bool WriteFileChecked(string path, Stream data, ref string sha1InOut, Can // suppressed due to only using for consistency checks using (var sha1 = SHA1.Create()) { - string GetSha1(Stream dataToHash) + string? GetSha1(Stream dataToHash) { if (dataToHash == null) return null; From 330217cbe3a09171ef95a77455e1ac6ae5890b31 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:54:24 -0500 Subject: [PATCH 511/717] Nullify `WindowsFilesystemLinkFactory` --- src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs b/src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs index 5a410ab3d79..6636838ab42 100644 --- a/src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs +++ b/src/Tgstation.Server.Host/IO/WindowsFilesystemLinkFactory.cs @@ -4,9 +4,8 @@ using System.Threading.Tasks; using BetterWin32Errors; -using Tgstation.Server.Host.System; -#nullable disable +using Tgstation.Server.Host.System; namespace Tgstation.Server.Host.IO { From ae505a207c2a0dea57ce20c2011cff1b9152a4b2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 14:54:45 -0500 Subject: [PATCH 512/717] Nullify `WindowsPostWriteHandler` --- src/Tgstation.Server.Host/IO/WindowsPostWriteHandler.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/WindowsPostWriteHandler.cs b/src/Tgstation.Server.Host/IO/WindowsPostWriteHandler.cs index a2b6b0d4ae0..2a94e42a2fe 100644 --- a/src/Tgstation.Server.Host/IO/WindowsPostWriteHandler.cs +++ b/src/Tgstation.Server.Host/IO/WindowsPostWriteHandler.cs @@ -1,7 +1,5 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.IO { /// From 960f2e4561917e3b1bc2102a5bfdaa3298d9adb0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 15:05:13 -0500 Subject: [PATCH 513/717] Nullify `SwarmRegistrationRequest` --- .../Swarm/SwarmRegistrationRequest.cs | 13 ++++++++++--- src/Tgstation.Server.Host/Swarm/SwarmService.cs | 3 +-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Swarm/SwarmRegistrationRequest.cs b/src/Tgstation.Server.Host/Swarm/SwarmRegistrationRequest.cs index 93f5ed92db5..229d4d28d20 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmRegistrationRequest.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmRegistrationRequest.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Api.Models.Internal; -#nullable disable - namespace Tgstation.Server.Host.Swarm { /// @@ -16,6 +14,15 @@ public sealed class SwarmRegistrationRequest : SwarmServer /// The TGS of the sending server. /// [Required] - public Version ServerVersion { get; set; } + public Version ServerVersion { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + public SwarmRegistrationRequest(Version serverVersion) + { + ServerVersion = serverVersion ?? throw new ArgumentNullException(nameof(serverVersion)); + } } } diff --git a/src/Tgstation.Server.Host/Swarm/SwarmService.cs b/src/Tgstation.Server.Host/Swarm/SwarmService.cs index cd0e855151a..0ff0131c723 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmService.cs @@ -1267,9 +1267,8 @@ async ValueTask RegisterWithController(CancellationToke null, HttpMethod.Post, SwarmConstants.RegisterRoute, - new SwarmRegistrationRequest + new SwarmRegistrationRequest(assemblyInformationProvider.Version) { - ServerVersion = assemblyInformationProvider.Version, Identifier = swarmConfiguration.Identifier, Address = swarmConfiguration.Address, PublicAddress = swarmConfiguration.PublicAddress, From c9b236da67ba5ee4701c6ced919cafabc3db71eb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 15:11:40 -0500 Subject: [PATCH 514/717] Nullify `ChatBot` --- .../Components/Chat/ChatManager.cs | 3 +-- .../Controllers/ChatController.cs | 10 +++---- src/Tgstation.Server.Host/Models/ChatBot.cs | 26 +++++++++++++++---- .../Chat/Providers/TestDiscordProvider.cs | 1 + .../Chat/Providers/TestIrcProvider.cs | 1 + 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index b6000a7619c..b0586d81a9b 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -327,7 +327,7 @@ public async ValueTask ChangeSettings(Models.ChatBot newSettings, CancellationTo if (originalChatBot != null) activeChatBots.Remove(originalChatBot); - activeChatBots.Add(new Models.ChatBot + activeChatBots.Add(new Models.ChatBot(newSettings.Channels) { Id = newSettings.Id, ConnectionString = newSettings.ConnectionString, @@ -335,7 +335,6 @@ public async ValueTask ChangeSettings(Models.ChatBot newSettings, CancellationTo Name = newSettings.Name, ReconnectionInterval = newSettings.ReconnectionInterval, Provider = newSettings.Provider, - Channels = newSettings.Channels, }); } diff --git a/src/Tgstation.Server.Host/Controllers/ChatController.cs b/src/Tgstation.Server.Host/Controllers/ChatController.cs index 6b35f19d284..6bae07a4442 100644 --- a/src/Tgstation.Server.Host/Controllers/ChatController.cs +++ b/src/Tgstation.Server.Host/Controllers/ChatController.cs @@ -126,12 +126,12 @@ public async ValueTask Create([FromBody] ChatBotCreateRequest mod model.ReconnectionInterval ??= 1; // try to update das db first - var dbModel = new ChatBot + var newChannels = model.Channels?.Select(x => ConvertApiChatChannel(x, model.Provider!.Value)).ToList() ?? new List(); // important that this isn't null + var dbModel = new ChatBot(newChannels) { Name = model.Name, ConnectionString = model.ConnectionString, Enabled = model.Enabled, - Channels = model.Channels?.Select(x => ConvertApiChatChannel(x, model.Provider!.Value)).ToList() ?? new List(), // important that this isn't null InstanceId = Instance.Id!.Value, Provider = model.Provider, ReconnectionInterval = model.ReconnectionInterval, @@ -296,7 +296,7 @@ public async ValueTask Update([FromBody] ChatBotUpdateRequest mod if (current == default) return this.Gone(); - if ((model.Channels?.Count ?? current.Channels.Count) > (model.ChannelLimit ?? current.ChannelLimit!.Value)) + if ((model.Channels?.Count ?? current.Channels!.Count) > (model.ChannelLimit ?? current.ChannelLimit!.Value)) { // 400 or 409 depends on if the client sent both var errorMessage = new ErrorMessageResponse(ErrorCode.ChatBotMaxChannels); @@ -339,7 +339,7 @@ bool CheckModified(Expression> expression, ChatBotRi var hasChannels = model.Channels != null; if (hasChannels || (model.Provider.HasValue && model.Provider != oldProvider)) { - DatabaseContext.ChatChannels.RemoveRange(current.Channels); + DatabaseContext.ChatChannels.RemoveRange(current.Channels!); if (hasChannels) { var dbChannels = model.Channels!.Select(x => ConvertApiChatChannel(x, model.Provider ?? current.Provider!.Value)).ToList(); @@ -347,7 +347,7 @@ bool CheckModified(Expression> expression, ChatBotRi current.Channels = dbChannels; } else - current.Channels.Clear(); + current.Channels!.Clear(); } await DatabaseContext.Save(cancellationToken); diff --git a/src/Tgstation.Server.Host/Models/ChatBot.cs b/src/Tgstation.Server.Host/Models/ChatBot.cs index 8b5fe59f7db..fb31ff5032c 100644 --- a/src/Tgstation.Server.Host/Models/ChatBot.cs +++ b/src/Tgstation.Server.Host/Models/ChatBot.cs @@ -1,11 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -25,17 +24,34 @@ public sealed class ChatBot : Api.Models.Internal.ChatBotSettings, IApiTransform /// The parent . /// [Required] - public Instance Instance { get; set; } + public Instance? Instance { get; set; } /// /// See . /// public ICollection Channels { get; set; } + /// + /// Initializes a new instance of the class. + /// + public ChatBot() + : this(new List()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + public ChatBot(ICollection channels) + { + Channels = channels ?? throw new ArgumentNullException(nameof(channels)); + } + /// public ChatBotResponse ToApi() => new ChatBotResponse { - Channels = Channels.Select(x => x.ToApi(Provider.Value)).ToList(), + Channels = Channels.Select(x => x.ToApi(this.Require(x => x.Provider))).ToList(), ConnectionString = ConnectionString, Enabled = Enabled, Provider = Provider, diff --git a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs index b21b19f0aee..61d61a19a3a 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Reflection; using System.Threading; using System.Threading.Tasks; diff --git a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs index 9e8565955e8..60021ea0194 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Reflection; using System.Threading; using System.Threading.Tasks; From f6083fcf6608bf72c7459b85e4ed8e1d9cc584ed Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 15:15:31 -0500 Subject: [PATCH 515/717] Clean up a method signature --- src/Tgstation.Server.Host/Controllers/ChatController.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ChatController.cs b/src/Tgstation.Server.Host/Controllers/ChatController.cs index 6bae07a4442..9ea7f4f5a70 100644 --- a/src/Tgstation.Server.Host/Controllers/ChatController.cs +++ b/src/Tgstation.Server.Host/Controllers/ChatController.cs @@ -281,7 +281,7 @@ public async ValueTask Update([FromBody] ChatBotUpdateRequest mod { ArgumentNullException.ThrowIfNull(model); - var earlyOut = StandardModelChecks(model, false); + IActionResult? earlyOut = StandardModelChecks(model, false); if (earlyOut != null) return earlyOut; @@ -382,8 +382,8 @@ bool CheckModified(Expression> expression, ChatBotRi /// /// The to validate. /// If the is being created. - /// An to respond with or . - IActionResult? StandardModelChecks(ChatBotApiBase model, bool forCreation) + /// An to respond with or . + BadRequestObjectResult? StandardModelChecks(ChatBotApiBase model, bool forCreation) { if (model.ReconnectionInterval == 0) throw new InvalidOperationException("RecconnectionInterval cannot be zero!"); From 9a69af5a861ada4db937cc06eed7ee2b5babe696 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 15:17:23 -0500 Subject: [PATCH 516/717] Nullify `ChatChannel` --- src/Tgstation.Server.Host/Models/ChatChannel.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/ChatChannel.cs b/src/Tgstation.Server.Host/Models/ChatChannel.cs index 85823089cfa..9263d2f9a60 100644 --- a/src/Tgstation.Server.Host/Models/ChatChannel.cs +++ b/src/Tgstation.Server.Host/Models/ChatChannel.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -25,7 +23,7 @@ public sealed class ChatChannel : ChatChannelBase /// The IRC channel name. /// [StringLength(Limits.MaximumIndexableStringLength, MinimumLength = 1)] - public string IrcChannel { get; set; } + public string? IrcChannel { get; set; } /// /// The Discord channel snowflake. @@ -35,16 +33,16 @@ public sealed class ChatChannel : ChatChannelBase /// /// The . /// - public ChatBot ChatSettings { get; set; } + public ChatBot? ChatSettings { get; set; } /// /// Convert to a . /// /// The channel's . /// The converted . - public Api.Models.ChatChannel ToApi(ChatProvider chatProvider) => new Api.Models.ChatChannel + public Api.Models.ChatChannel ToApi(ChatProvider chatProvider) => new() { - ChannelData = chatProvider == ChatProvider.Discord ? DiscordChannelId.Value.ToString(CultureInfo.InvariantCulture) : IrcChannel, + ChannelData = chatProvider == ChatProvider.Discord ? DiscordChannelId!.Value.ToString(CultureInfo.InvariantCulture) : IrcChannel, IsAdminChannel = IsAdminChannel, IsWatchdogChannel = IsWatchdogChannel, IsUpdatesChannel = IsUpdatesChannel, From 082990927a680bafeb491a866585b627ced048f6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 15:30:06 -0500 Subject: [PATCH 517/717] Nullify `CompileJob` --- .../Components/Deployment/DreamMaker.cs | 14 ++--- .../Models/CompileJob.cs | 51 +++++++++++++++++-- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index 5d994636371..a36068a8259 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -317,6 +317,7 @@ await databaseContextFactory.UseContext( && repositorySettings.AccessUser != null; using (repo) compileJob = await Compile( + job, revInfo, dreamMakerSettings, ddSettings, @@ -447,6 +448,7 @@ await databaseContextFactory.UseContext( /// /// Run the compile implementation. /// + /// The currently running . /// The . /// The . /// The . @@ -458,6 +460,7 @@ await databaseContextFactory.UseContext( /// The for the operation. /// A resulting in the completed . async ValueTask Compile( + Models.Job job, Models.RevisionInformation revisionInformation, Api.Models.Internal.DreamMakerSettings dreamMakerSettings, DreamDaemonLaunchParameters launchParameters, @@ -485,19 +488,16 @@ await databaseContextFactory.UseContext( repository.RemoteRepositoryName, localCommitExistsOnRemote); - var job = new Models.CompileJob + var compileJob = new Models.CompileJob(job, revisionInformation, engineLock.Version.ToString(), repository.Origin.ToString()) { DirectoryName = Guid.NewGuid(), DmeName = dreamMakerSettings.ProjectName, - RevisionInformation = revisionInformation, - EngineVersion = engineLock.Version.ToString(), - RepositoryOrigin = repository.Origin.ToString(), }; progressReporter.StageName = "Creating remote deployment notification"; await remoteDeploymentManager.StartDeployment( repository, - job, + compileJob, cancellationToken); logger.LogTrace("Deployment will timeout at {timeoutTime}", DateTimeOffset.UtcNow + dreamMakerSettings.Timeout.Value); @@ -510,7 +510,7 @@ await remoteDeploymentManager.StartDeployment( { await RunCompileJob( progressReporter, - job, + compileJob, dreamMakerSettings, launchParameters, engineLock, @@ -524,7 +524,7 @@ await RunCompileJob( } } - return job; + return compileJob; } catch (OperationCanceledException) { diff --git a/src/Tgstation.Server.Host/Models/CompileJob.cs b/src/Tgstation.Server.Host/Models/CompileJob.cs index 5883302c591..ea729e9217d 100644 --- a/src/Tgstation.Server.Host/Models/CompileJob.cs +++ b/src/Tgstation.Server.Host/Models/CompileJob.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -65,14 +63,14 @@ public sealed class CompileJob : Api.Models.Internal.CompileJob, IApiTransformab public int? GitHubDeploymentId { get; set; } /// - public override Version DMApiVersion + public override Version? DMApiVersion { get { if (!DMApiMajorVersion.HasValue) return null; - return new Version(DMApiMajorVersion.Value, DMApiMinorVersion.Value, DMApiPatchVersion.Value); + return new Version(DMApiMajorVersion.Value, DMApiMinorVersion!.Value, DMApiPatchVersion!.Value); } set @@ -83,6 +81,51 @@ public override Version DMApiVersion } } + /// + /// Initializes a new instance of the class. + /// + [Obsolete("For use by EFCore only", true)] + public CompileJob() + : this(null!, null!, null!, null!, false) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + /// The value of . + /// The value of . + public CompileJob(Job job, RevisionInformation revisionInformation, string engineVersion, string repositoryOrigin) + : this(job, revisionInformation, engineVersion, repositoryOrigin, true) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + /// The value of . + /// The value of . + /// If , , and should be checked for nulls. + CompileJob(Job job, RevisionInformation revisionInformation, string engineVersion, string repositoryOrigin, bool nullChecks) + { + if (nullChecks) + { + ArgumentNullException.ThrowIfNull(job); + ArgumentNullException.ThrowIfNull(revisionInformation); + ArgumentNullException.ThrowIfNull(engineVersion); + ArgumentNullException.ThrowIfNull(repositoryOrigin); + } + + Job = job; + RevisionInformation = revisionInformation; + EngineVersion = engineVersion; + RepositoryOrigin = repositoryOrigin; + } + /// public CompileJobResponse ToApi() => new() { From dd23015f4a431df9e8a140c1ecb3c643cd1ad45b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 15:57:57 -0500 Subject: [PATCH 518/717] Slightly increase the health check timeout --- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index d182e542a33..0df8a9755c6 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -771,7 +771,7 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke .GetProcess(ddProc.Id); // Ensure it's responding to health checks - await Task.WhenAny(Task.Delay(6000, cancellationToken), ourProcessHandler.Lifetime); + await Task.WhenAny(Task.Delay(7000, cancellationToken), ourProcessHandler.Lifetime); Assert.IsFalse(ddProc.HasExited); // check DD agrees From d169c2162471513bd7745f918076cd698265e2c0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 16:23:45 -0500 Subject: [PATCH 519/717] Nullify `DreamDaemonSettings` --- src/Tgstation.Server.Host/Models/DreamDaemonSettings.cs | 4 +--- src/Tgstation.Server.Host/Utils/PortAllocator.cs | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/DreamDaemonSettings.cs b/src/Tgstation.Server.Host/Models/DreamDaemonSettings.cs index c58642fd956..0da7f220796 100644 --- a/src/Tgstation.Server.Host/Models/DreamDaemonSettings.cs +++ b/src/Tgstation.Server.Host/Models/DreamDaemonSettings.cs @@ -1,7 +1,5 @@ using System.ComponentModel.DataAnnotations; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -21,6 +19,6 @@ public sealed class DreamDaemonSettings : Api.Models.Internal.DreamDaemonSetting /// The parent . /// [Required] - public Instance Instance { get; set; } + public Instance? Instance { get; set; } } } diff --git a/src/Tgstation.Server.Host/Utils/PortAllocator.cs b/src/Tgstation.Server.Host/Utils/PortAllocator.cs index 310cfbfe3da..1aa096ab0b1 100644 --- a/src/Tgstation.Server.Host/Utils/PortAllocator.cs +++ b/src/Tgstation.Server.Host/Utils/PortAllocator.cs @@ -74,14 +74,14 @@ public PortAllocator( var ddPorts = await databaseContext .DreamDaemonSettings .AsQueryable() - .Where(x => x.Instance.SwarmIdentifer == swarmConfiguration.Identifier) + .Where(x => x.Instance!.SwarmIdentifer == swarmConfiguration.Identifier) .Select(x => x.Port) .ToListAsync(cancellationToken); var dmPorts = await databaseContext .DreamMakerSettings .AsQueryable() - .Where(x => x.Instance.SwarmIdentifer == swarmConfiguration.Identifier) + .Where(x => x.Instance!.SwarmIdentifer == swarmConfiguration.Identifier) .Select(x => x.ApiValidationPort) .ToListAsync(cancellationToken); From 2f9531ed9f5b3e68411d75ae5a2f96b7302fa1cc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 16:24:09 -0500 Subject: [PATCH 520/717] Nullify `DreamMakerSettings` --- src/Tgstation.Server.Host/Models/DreamMakerSettings.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/DreamMakerSettings.cs b/src/Tgstation.Server.Host/Models/DreamMakerSettings.cs index 88bfe61344b..4cc7998e413 100644 --- a/src/Tgstation.Server.Host/Models/DreamMakerSettings.cs +++ b/src/Tgstation.Server.Host/Models/DreamMakerSettings.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -23,7 +21,7 @@ public sealed class DreamMakerSettings : Api.Models.Internal.DreamMakerSettings, /// The parent . /// [Required] - public Instance Instance { get; set; } + public Instance? Instance { get; set; } /// public DreamMakerResponse ToApi() => new DreamMakerResponse From aee739cfb0c6cc779d9eda5ed46a96f04e0f55ee Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 16:26:18 -0500 Subject: [PATCH 521/717] Cleanup another ValueTask message --- .../Components/Deployment/DreamMaker.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index a36068a8259..255c07dd543 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -967,13 +967,16 @@ async ValueTask CleanDir() } } - // DCT: None available + var dirCleanTask = CleanDir(); + + var failRemoteDeployTask = remoteDeploymentManager.FailDeployment( + job, + FormatExceptionForUsers(exception), + CancellationToken.None); // DCT: None available + return ValueTaskExtensions.WhenAll( - CleanDir(), - remoteDeploymentManager.FailDeployment( - job, - FormatExceptionForUsers(exception), - CancellationToken.None)); + dirCleanTask, + failRemoteDeployTask); } } } From 4a7d675cb3bff57c6a68da16568a0452d63f0593 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 16:29:35 -0500 Subject: [PATCH 522/717] Nullify `Instance` --- src/Tgstation.Server.Host/Models/Instance.cs | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/Instance.cs b/src/Tgstation.Server.Host/Models/Instance.cs index d098b60e700..a96470e9fa8 100644 --- a/src/Tgstation.Server.Host/Models/Instance.cs +++ b/src/Tgstation.Server.Host/Models/Instance.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -19,22 +17,22 @@ public sealed class Instance : Api.Models.Instance, IApiTransformable /// The for the . /// - public DreamMakerSettings DreamMakerSettings { get; set; } + public DreamMakerSettings? DreamMakerSettings { get; set; } /// /// The for the . /// - public DreamDaemonSettings DreamDaemonSettings { get; set; } + public DreamDaemonSettings? DreamDaemonSettings { get; set; } /// /// The for the . /// - public RepositorySettings RepositorySettings { get; set; } + public RepositorySettings? RepositorySettings { get; set; } /// /// The of the the server in the swarm this instance belongs to. /// - public string SwarmIdentifer { get; set; } + public string? SwarmIdentifer { get; set; } /// /// The s in the . @@ -56,6 +54,17 @@ public sealed class Instance : Api.Models.Instance, IApiTransformable public ICollection Jobs { get; set; } + /// + /// Initializes a new instance of the class. + /// + public Instance() + { + InstancePermissionSets = new List(); + ChatSettings = new List(); + RevisionInformations = new List(); + Jobs = new List(); + } + /// public InstanceResponse ToApi() => new() { From 9ea0b7bed93e4d2ccf5a87cf9fd8ce2509986001 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 16:30:53 -0500 Subject: [PATCH 523/717] Simplify some `new()` expressions --- src/Tgstation.Server.Host/Models/ChatBot.cs | 2 +- src/Tgstation.Server.Host/Models/DreamMakerSettings.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/ChatBot.cs b/src/Tgstation.Server.Host/Models/ChatBot.cs index fb31ff5032c..caf1f0c645f 100644 --- a/src/Tgstation.Server.Host/Models/ChatBot.cs +++ b/src/Tgstation.Server.Host/Models/ChatBot.cs @@ -49,7 +49,7 @@ public ChatBot(ICollection channels) } /// - public ChatBotResponse ToApi() => new ChatBotResponse + public ChatBotResponse ToApi() => new() { Channels = Channels.Select(x => x.ToApi(this.Require(x => x.Provider))).ToList(), ConnectionString = ConnectionString, diff --git a/src/Tgstation.Server.Host/Models/DreamMakerSettings.cs b/src/Tgstation.Server.Host/Models/DreamMakerSettings.cs index 4cc7998e413..72f5a99f29c 100644 --- a/src/Tgstation.Server.Host/Models/DreamMakerSettings.cs +++ b/src/Tgstation.Server.Host/Models/DreamMakerSettings.cs @@ -24,7 +24,7 @@ public sealed class DreamMakerSettings : Api.Models.Internal.DreamMakerSettings, public Instance? Instance { get; set; } /// - public DreamMakerResponse ToApi() => new DreamMakerResponse + public DreamMakerResponse ToApi() => new() { ProjectName = ProjectName, ApiValidationPort = ApiValidationPort, From 3a6047702f6bc1534fad80f43e22539f4404e4c7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 19:31:29 -0500 Subject: [PATCH 524/717] Nullify `InstancePermissionSet` --- src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs | 2 +- src/Tgstation.Server.Host/Models/InstancePermissionSet.cs | 8 +++----- .../Security/AuthenticationContextFactory.cs | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs b/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs index 1342091caac..6264c185d78 100644 --- a/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs +++ b/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs @@ -67,7 +67,7 @@ public JobsHubGroupMapper( public ValueTask InstancePermissionSetCreated(InstancePermissionSet instancePermissionSet, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(instancePermissionSet); - var permissionSetId = instancePermissionSet.PermissionSet.Id ?? instancePermissionSet.PermissionSetId; + var permissionSetId = instancePermissionSet.PermissionSetId; logger.LogTrace("InstancePermissionSetCreated"); return RefreshHubGroups( diff --git a/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs b/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs index 01bc99ae428..8db1f17fba4 100644 --- a/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs +++ b/src/Tgstation.Server.Host/Models/InstancePermissionSet.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -23,16 +21,16 @@ public sealed class InstancePermissionSet : Api.Models.Internal.InstancePermissi /// The the belongs to. /// [Required] - public Instance Instance { get; set; } + public Instance? Instance { get; set; } /// /// The the belongs to. /// [Required] - public PermissionSet PermissionSet { get; set; } + public PermissionSet? PermissionSet { get; set; } /// - public InstancePermissionSetResponse ToApi() => new InstancePermissionSetResponse + public InstancePermissionSetResponse ToApi() => new() { EngineRights = EngineRights, ChatBotRights = ChatBotRights, diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs b/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs index 8dca0248c77..7fa7b2802f8 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs @@ -119,7 +119,7 @@ public async ValueTask CreateAuthenticationContext(long { instancePermissionSet = await databaseContext.InstancePermissionSets .AsQueryable() - .Where(x => x.PermissionSetId == userPermissionSet.Id && x.InstanceId == instanceId && x.Instance.SwarmIdentifer == swarmConfiguration.Identifier) + .Where(x => x.PermissionSetId == userPermissionSet.Id && x.InstanceId == instanceId && x.Instance!.SwarmIdentifer == swarmConfiguration.Identifier) .Include(x => x.Instance) .FirstOrDefaultAsync(cancellationToken); From 8fc4c36fd35fdab9c73fbf5fd9c829f739dc3dfe Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 19:48:09 -0500 Subject: [PATCH 525/717] Nullify `Job` --- .../Components/Chat/Providers/Provider.cs | 5 ++++- src/Tgstation.Server.Host/Jobs/JobService.cs | 5 ++++- src/Tgstation.Server.Host/Models/Job.cs | 22 +++++++++---------- .../Chat/Providers/TestDiscordProvider.cs | 9 +++++--- .../Chat/Providers/TestIrcProvider.cs | 6 ++--- 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs index da4deecd111..4123521ad79 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs @@ -96,6 +96,9 @@ protected Provider(IJobManager jobManager, IAsyncDelayer asyncDelayer, ILogger

(); nextMessage = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); initialConnectionTcs = new TaskCompletionSource(); @@ -286,7 +289,7 @@ async Task ReconnectionLoop(uint reconnectInterval, bool connectNow, Cancellatio connectNow = false; if (!Connected) { - var job = Job.Create(Api.Models.JobCode.ReconnectChatBot, null, ChatBot.Instance, ChatBotRights.WriteEnabled); + var job = Job.Create(Api.Models.JobCode.ReconnectChatBot, null, ChatBot.Instance!, ChatBotRights.WriteEnabled); job.Description += $": {ChatBot.Name}"; await jobManager.RegisterOperation( diff --git a/src/Tgstation.Server.Host/Jobs/JobService.cs b/src/Tgstation.Server.Host/Jobs/JobService.cs index 0e8714e307a..ea2782a8218 100644 --- a/src/Tgstation.Server.Host/Jobs/JobService.cs +++ b/src/Tgstation.Server.Host/Jobs/JobService.cs @@ -123,6 +123,9 @@ public async ValueTask RegisterOperation(Job job, JobEntrypoint operation, Cance if (job.StartedBy != null && job.StartedBy.Name == null) throw new InvalidOperationException("StartedBy User associated with job does not have a Name!"); + if (job.Instance == null) + throw new InvalidOperationException("No Instance associated with job!"); + job.StartedAt = DateTimeOffset.UtcNow; job.Cancelled = false; @@ -458,7 +461,7 @@ void UpdateProgress(string? stage, double? progress) logger.LogTrace("Starting job..."); await operation( - instanceCoreProvider.GetInstance(job.Instance), + instanceCoreProvider.GetInstance(job.Instance!), databaseContextFactory, job, new JobProgressReporter( diff --git a/src/Tgstation.Server.Host/Models/Job.cs b/src/Tgstation.Server.Host/Models/Job.cs index c9af1ffa508..85327de2e27 100644 --- a/src/Tgstation.Server.Host/Models/Job.cs +++ b/src/Tgstation.Server.Host/Models/Job.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Api.Rights; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -20,18 +18,18 @@ public sealed class Job : Api.Models.Internal.Job, IApiTransformable. ///

[Required] - public User StartedBy { get; set; } + public User? StartedBy { get; set; } /// /// See . /// - public User CancelledBy { get; set; } + public User? CancelledBy { get; set; } /// /// The the job belongs to if any. /// [Required] - public Instance Instance { get; set; } + public Instance? Instance { get; set; } /// /// Creates a new job for registering in the . @@ -42,7 +40,7 @@ public sealed class Job : Api.Models.Internal.Job, IApiTransformableThe used to generate the value of . /// The value of . will be derived from this. /// A new ready to be registered with the . - public static Job Create(JobCode code, User startedBy, Api.Models.Instance instance, TRight cancelRight) + public static Job Create(JobCode code, User? startedBy, Api.Models.Instance instance, TRight cancelRight) where TRight : Enum => new( code, @@ -58,7 +56,7 @@ public static Job Create(JobCode code, User startedBy, Api.Models.Instan /// The value of . If , the user will be used. /// The used to generate the value of . /// A new ready to be registered with the . - public static Job Create(JobCode code, User startedBy, Api.Models.Instance instance) + public static Job Create(JobCode code, User? startedBy, Api.Models.Instance instance) => new( code, startedBy, @@ -91,7 +89,7 @@ public Job(long id) /// The value of . /// The value of . /// The value of . - Job(JobCode code, User startedBy, Api.Models.Instance instance, RightsType? cancelRightsType, ulong? cancelRight) + Job(JobCode code, User? startedBy, Api.Models.Instance instance, RightsType? cancelRightsType, ulong? cancelRight) { StartedBy = startedBy; ArgumentNullException.ThrowIfNull(instance); @@ -100,7 +98,7 @@ public Job(long id) Id = instance.Id ?? throw new InvalidOperationException("Instance associated with job does not have an Id!"), }; Description = typeof(JobCode) - .GetField(code.ToString()) + .GetField(code.ToString())! .GetCustomAttributes(false) .OfType() .First() @@ -114,8 +112,8 @@ public Job(long id) public JobResponse ToApi() => new() { Id = Id, - JobCode = JobCode.Value, - InstanceId = Instance.Id.Value, + JobCode = this.Require(x => x.JobCode), + InstanceId = (Instance ?? throw new InvalidOperationException("Instance needs to be set!")).Require(x => x.Id), StartedAt = StartedAt, StoppedAt = StoppedAt, Cancelled = Cancelled, @@ -125,7 +123,7 @@ public Job(long id) Description = Description, ExceptionDetails = ExceptionDetails, ErrorCode = ErrorCode, - StartedBy = StartedBy.CreateUserName(), + StartedBy = (StartedBy ?? throw new InvalidOperationException("StartedBy needs to be set!")).CreateUserName(), }; } } diff --git a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs index 61d61a19a3a..58c63c6a998 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestDiscordProvider.cs @@ -1,11 +1,11 @@ using System; -using System.Collections.Generic; using System.Reflection; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; using Tgstation.Server.Api.Models; @@ -31,7 +31,8 @@ public static void Initialize(TestContext _) testToken1 = new ChatBot { ConnectionString = actualToken, - ReconnectionInterval = 1 + ReconnectionInterval = 1, + Instance = new Models.Instance() }; var mockSetup = new Mock(); @@ -52,6 +53,7 @@ public async Task TestConstructionAndDisposal() { ConnectionString = "fake_token", ReconnectionInterval = 1, + Instance = new Models.Instance(), }; Assert.ThrowsException(() => new DiscordProvider(null, null, null, null, null, null)); @@ -76,7 +78,8 @@ public async Task TestConnectWithFakeTokenFails() await using var provider = new DiscordProvider(mockJobManager, Mock.Of(), mockLogger.Object, Mock.Of(), new ChatBot { ReconnectionInterval = 1, - ConnectionString = "asdf" + ConnectionString = "asdf", + Instance = new Models.Instance(), }, new GeneralConfiguration()); await Assert.ThrowsExceptionAsync(async () => await InvokeConnect(provider)); Assert.IsFalse(provider.Connected); diff --git a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs index 60021ea0194..3f1e0502191 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs @@ -1,14 +1,12 @@ using System; -using System.Collections.Generic; using System.Reflection; using System.Threading; using System.Threading.Tasks; -using System.Xml.Linq; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Serilog.Parsing; using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Jobs; @@ -37,6 +35,7 @@ public async Task TestConstructionAndDisposal() var mockBot = new ChatBot { Name = "test", + Instance = new Models.Instance(), Provider = ChatProvider.Irc }; @@ -83,6 +82,7 @@ public async Task TestConnectAndDisconnect() { ConnectionString = actualToken, Provider = ChatProvider.Irc, + Instance = new Models.Instance(), }); Assert.IsFalse(provider.Connected); await InvokeConnect(provider); From d7b2d27934ebc1e2980c00aae448dd57672c79a7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 19:49:36 -0500 Subject: [PATCH 526/717] Nullify `OAuthConnection` --- src/Tgstation.Server.Host/Models/OAuthConnection.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/OAuthConnection.cs b/src/Tgstation.Server.Host/Models/OAuthConnection.cs index df9a15732eb..d622b358c85 100644 --- a/src/Tgstation.Server.Host/Models/OAuthConnection.cs +++ b/src/Tgstation.Server.Host/Models/OAuthConnection.cs @@ -1,6 +1,4 @@ -#nullable disable - -namespace Tgstation.Server.Host.Models +namespace Tgstation.Server.Host.Models { /// public sealed class OAuthConnection : Api.Models.OAuthConnection, IApiTransformable @@ -13,10 +11,10 @@ public sealed class OAuthConnection : Api.Models.OAuthConnection, IApiTransforma /// /// The owning . /// - public User User { get; set; } + public User? User { get; set; } /// - public Api.Models.OAuthConnection ToApi() => new Api.Models.OAuthConnection + public Api.Models.OAuthConnection ToApi() => new() { Provider = Provider, ExternalUserId = ExternalUserId, From 5ef00c3988807e4493d503532b4fc311b6814e25 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 20:46:33 -0500 Subject: [PATCH 527/717] Nullify `PermissionSet` --- src/Tgstation.Server.Host/Models/PermissionSet.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/PermissionSet.cs b/src/Tgstation.Server.Host/Models/PermissionSet.cs index 704412c1742..554956dd32a 100644 --- a/src/Tgstation.Server.Host/Models/PermissionSet.cs +++ b/src/Tgstation.Server.Host/Models/PermissionSet.cs @@ -1,7 +1,5 @@ using System.Collections.Generic; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -20,17 +18,17 @@ public sealed class PermissionSet : Api.Models.PermissionSet /// /// The the belongs to, if it is for a . /// - public User User { get; set; } + public User? User { get; set; } /// /// The the belongs to, if it is for a . /// - public UserGroup Group { get; set; } + public UserGroup? Group { get; set; } /// /// The s associated with the . /// - public ICollection InstancePermissionSets { get; set; } + public ICollection? InstancePermissionSets { get; set; } /// /// Convert the to it's API form. From f308112937d2201fcf1ee2ec5a8e2c5b63e4c126 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 20:46:57 -0500 Subject: [PATCH 528/717] Nullify `ReattachInformation` --- src/Tgstation.Server.Host/Models/ReattachInformation.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/ReattachInformation.cs b/src/Tgstation.Server.Host/Models/ReattachInformation.cs index 80137b50048..9454e4acf6c 100644 --- a/src/Tgstation.Server.Host/Models/ReattachInformation.cs +++ b/src/Tgstation.Server.Host/Models/ReattachInformation.cs @@ -1,7 +1,5 @@ using System.ComponentModel.DataAnnotations; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -13,7 +11,7 @@ public sealed class ReattachInformation : ReattachInformationBase /// The for the . /// [Required] - public CompileJob CompileJob { get; set; } + public CompileJob? CompileJob { get; set; } /// /// The of . @@ -23,7 +21,7 @@ public sealed class ReattachInformation : ReattachInformationBase /// /// The the server was initially launched with in the case of Windows. /// - public CompileJob InitialCompileJob { get; set; } + public CompileJob? InitialCompileJob { get; set; } /// /// The of . From 3520f33b82a6d03c72d117c7f91339eaced2f878 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 20:47:19 -0500 Subject: [PATCH 529/717] Nullify `ReattachInformationBase` --- src/Tgstation.Server.Host/Models/ReattachInformationBase.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs b/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs index 0f8106aa7b0..b233f0c0179 100644 --- a/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs +++ b/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Session; -#nullable disable - namespace Tgstation.Server.Host.Models { /// From eefdc4741054c59dc3dea09442da1aead88d877b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 22:35:24 -0500 Subject: [PATCH 530/717] Nullify `RepositorySettings` --- src/Tgstation.Server.Host/Models/RepositorySettings.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/RepositorySettings.cs b/src/Tgstation.Server.Host/Models/RepositorySettings.cs index c5e1d904c25..78e2aada1a7 100644 --- a/src/Tgstation.Server.Host/Models/RepositorySettings.cs +++ b/src/Tgstation.Server.Host/Models/RepositorySettings.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -23,7 +21,7 @@ public sealed class RepositorySettings : Api.Models.Internal.RepositorySettings, /// The parent . /// [Required] - public Instance Instance { get; set; } + public Instance? Instance { get; set; } /// public RepositoryResponse ToApi() => new RepositoryResponse From 47c919052696008c331a9cbcfa604e1e5d3f2e35 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 22:39:50 -0500 Subject: [PATCH 531/717] Nullify `ReviInfoTestMerge` --- .../Components/Instance.cs | 5 +--- .../Repository/RepositoryUpdateService.cs | 5 +--- .../Models/RevInfoTestMerge.cs | 26 ++++++++++++++++--- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 10b0e89cd7a..e1421476d12 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -368,10 +368,7 @@ async ValueTask UpdateRevInfo(string currentHead, bool onOrigin, IEnumerable x.TestMerge); var revInfoTestMerges = testMerges.Select( - testMerge => new RevInfoTestMerge - { - TestMerge = testMerge, - }) + testMerge => new RevInfoTestMerge(testMerge, currentRevInfo)) .ToList(); currentRevInfo.ActiveTestMerges = revInfoTestMerges; diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs index 8b00701f69c..130718f9e59 100644 --- a/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs +++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs @@ -228,10 +228,7 @@ ValueTask CallLoadRevInfo(Models.TestMerge testMergeToAdd = null, string lastOri foreach (var activeTestMerge in previousRevInfo.ActiveTestMerges) lastRevisionInfo.ActiveTestMerges.Add(activeTestMerge); - lastRevisionInfo.ActiveTestMerges.Add(new RevInfoTestMerge - { - TestMerge = testMergeToAdd, - }); + lastRevisionInfo.ActiveTestMerges.Add(new RevInfoTestMerge(testMergeToAdd, lastRevisionInfo)); lastRevisionInfo.PrimaryTestMerge = testMergeToAdd; needsUpdate = true; diff --git a/src/Tgstation.Server.Host/Models/RevInfoTestMerge.cs b/src/Tgstation.Server.Host/Models/RevInfoTestMerge.cs index 64b088343aa..bed334b0bc8 100644 --- a/src/Tgstation.Server.Host/Models/RevInfoTestMerge.cs +++ b/src/Tgstation.Server.Host/Models/RevInfoTestMerge.cs @@ -1,6 +1,5 @@ -using System.ComponentModel.DataAnnotations; - -#nullable disable +using System; +using System.ComponentModel.DataAnnotations; namespace Tgstation.Server.Host.Models { @@ -25,5 +24,26 @@ public sealed class RevInfoTestMerge /// [Required] public RevisionInformation RevisionInformation { get; set; } + + /// + /// Initializes a new instance of the class. + /// + [Obsolete("For use by EFCore only", true)] + public RevInfoTestMerge() + { + TestMerge = null!; + RevisionInformation = null!; + } + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + public RevInfoTestMerge(TestMerge testMerge, RevisionInformation revisionInformation) + { + TestMerge = testMerge ?? throw new ArgumentNullException(nameof(testMerge)); + RevisionInformation = revisionInformation ?? throw new ArgumentNullException(nameof(revisionInformation)); + } } } From daed19610443ed0e0fd3f9e0a9e5963d8518f1e2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 22:41:59 -0500 Subject: [PATCH 532/717] Nullify `RevisionInformation` --- .../Chat/Commands/PullRequestsCommand.cs | 6 +++--- .../Models/RevisionInformation.cs | 17 ++++++++--------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs index c4022d95d77..3fd8c9e64bf 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/PullRequestsCommand.cs @@ -117,8 +117,8 @@ await databaseContextFactory.UseContext( async db => results = await db .RevisionInformations .AsQueryable() - .Where(x => x.Instance.Id == instance.Id && x.CommitSha == head) - .SelectMany(x => x.ActiveTestMerges) + .Where(x => x.Instance!.Id == instance.Id && x.CommitSha == head) + .SelectMany(x => x.ActiveTestMerges!) .Select(x => x.TestMerge) .Select(x => new Models.TestMerge { @@ -144,7 +144,7 @@ await databaseContextFactory.UseContext( compileJobToUse = null; } - results = compileJobToUse?.RevisionInformation.ActiveTestMerges.Select(x => x.TestMerge).ToList() ?? Enumerable.Empty(); + results = compileJobToUse?.RevisionInformation.ActiveTestMerges?.Select(x => x.TestMerge).ToList() ?? Enumerable.Empty(); } return new MessageContent diff --git a/src/Tgstation.Server.Host/Models/RevisionInformation.cs b/src/Tgstation.Server.Host/Models/RevisionInformation.cs index 8813e4c5bc9..cbc8b82ad70 100644 --- a/src/Tgstation.Server.Host/Models/RevisionInformation.cs +++ b/src/Tgstation.Server.Host/Models/RevisionInformation.cs @@ -1,9 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -23,22 +22,22 @@ public sealed class RevisionInformation : Api.Models.Internal.RevisionInformatio /// The the belongs to. /// [Required] - public Instance Instance { get; set; } + public Instance? Instance { get; set; } /// /// See . /// - public TestMerge PrimaryTestMerge { get; set; } + public TestMerge? PrimaryTestMerge { get; set; } /// /// See . /// - public ICollection ActiveTestMerges { get; set; } + public ICollection? ActiveTestMerges { get; set; } /// /// See s made from this . /// - public ICollection CompileJobs { get; set; } + public ICollection? CompileJobs { get; set; } /// public Api.Models.RevisionInformation ToApi() => new Api.Models.RevisionInformation @@ -47,8 +46,8 @@ public sealed class RevisionInformation : Api.Models.Internal.RevisionInformatio Timestamp = Timestamp, OriginCommitSha = OriginCommitSha, PrimaryTestMerge = PrimaryTestMerge?.ToApi(), - ActiveTestMerges = ActiveTestMerges.Select(x => x.TestMerge.ToApi()).ToList(), - CompileJobs = CompileJobs.Select(x => new Api.Models.EntityId + ActiveTestMerges = (ActiveTestMerges ?? throw new InvalidOperationException("ActiveTestMerges must be set!")).Select(x => x.TestMerge.ToApi()).ToList(), + CompileJobs = (CompileJobs ?? throw new InvalidOperationException("CompileJobs must be set!")).Select(x => new Api.Models.EntityId { Id = x.Id, }).ToList(), From 67417b6ec8e7b7da2ba28d7037a6f3958ebaecde Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 22:45:12 -0500 Subject: [PATCH 533/717] Nullify `TestMerge` --- src/Tgstation.Server.Host/Models/TestMerge.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/TestMerge.cs b/src/Tgstation.Server.Host/Models/TestMerge.cs index 3733ca62fcf..36416403789 100644 --- a/src/Tgstation.Server.Host/Models/TestMerge.cs +++ b/src/Tgstation.Server.Host/Models/TestMerge.cs @@ -1,8 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -12,13 +11,13 @@ public sealed class TestMerge : Api.Models.Internal.TestMergeApiBase, IApiTransf /// See . /// [Required] - public User MergedBy { get; set; } + public User? MergedBy { get; set; } /// /// The initial the was merged with. /// [Required] - public RevisionInformation PrimaryRevisionInformation { get; set; } + public RevisionInformation? PrimaryRevisionInformation { get; set; } /// /// Foreign key for . @@ -28,10 +27,10 @@ public sealed class TestMerge : Api.Models.Internal.TestMergeApiBase, IApiTransf /// /// All the for the . /// - public ICollection RevisonInformations { get; set; } + public ICollection? RevisonInformations { get; set; } /// - public Api.Models.TestMerge ToApi() => new Api.Models.TestMerge + public Api.Models.TestMerge ToApi() => new() { Author = Author, BodyAtMerge = BodyAtMerge, @@ -39,7 +38,7 @@ public sealed class TestMerge : Api.Models.Internal.TestMergeApiBase, IApiTransf TitleAtMerge = TitleAtMerge, Comment = Comment, Id = Id, - MergedBy = MergedBy.CreateUserName(), + MergedBy = (MergedBy ?? throw new InvalidOperationException("MergedBy must be set!")).CreateUserName(), Number = Number, TargetCommitSha = TargetCommitSha, Url = Url, From 029527494d4f1e8dd33a591e8ea1e5e98611fd70 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 22:45:21 -0500 Subject: [PATCH 534/717] Simplify some `new()` expressions --- src/Tgstation.Server.Host/Models/PermissionSet.cs | 2 +- src/Tgstation.Server.Host/Models/RepositorySettings.cs | 2 +- src/Tgstation.Server.Host/Models/RevisionInformation.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/PermissionSet.cs b/src/Tgstation.Server.Host/Models/PermissionSet.cs index 554956dd32a..2c18a2ae1f1 100644 --- a/src/Tgstation.Server.Host/Models/PermissionSet.cs +++ b/src/Tgstation.Server.Host/Models/PermissionSet.cs @@ -34,7 +34,7 @@ public sealed class PermissionSet : Api.Models.PermissionSet /// Convert the to it's API form. /// /// A new . - public Api.Models.PermissionSet ToApi() => new Api.Models.PermissionSet + public Api.Models.PermissionSet ToApi() => new() { Id = Id, AdministrationRights = AdministrationRights, diff --git a/src/Tgstation.Server.Host/Models/RepositorySettings.cs b/src/Tgstation.Server.Host/Models/RepositorySettings.cs index 78e2aada1a7..e8fb7f60197 100644 --- a/src/Tgstation.Server.Host/Models/RepositorySettings.cs +++ b/src/Tgstation.Server.Host/Models/RepositorySettings.cs @@ -24,7 +24,7 @@ public sealed class RepositorySettings : Api.Models.Internal.RepositorySettings, public Instance? Instance { get; set; } /// - public RepositoryResponse ToApi() => new RepositoryResponse + public RepositoryResponse ToApi() => new() { // AccessToken = AccessToken, // never show this AccessUser = AccessUser, diff --git a/src/Tgstation.Server.Host/Models/RevisionInformation.cs b/src/Tgstation.Server.Host/Models/RevisionInformation.cs index cbc8b82ad70..eb99816ab68 100644 --- a/src/Tgstation.Server.Host/Models/RevisionInformation.cs +++ b/src/Tgstation.Server.Host/Models/RevisionInformation.cs @@ -40,7 +40,7 @@ public sealed class RevisionInformation : Api.Models.Internal.RevisionInformatio public ICollection? CompileJobs { get; set; } /// - public Api.Models.RevisionInformation ToApi() => new Api.Models.RevisionInformation + public Api.Models.RevisionInformation ToApi() => new() { CommitSha = CommitSha, Timestamp = Timestamp, From 052b0b9e2633678953d4e60938ce1215ee876878 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 22:46:35 -0500 Subject: [PATCH 535/717] Cleanup some ChatManager messages --- src/Tgstation.Server.Host/Components/Chat/ChatManager.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index b0586d81a9b..505a94d8179 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -812,11 +812,9 @@ ValueTask TextReply(string reply) => SendMessage( if (address.Length > 1 && (address.Last() == ':' || address.Last() == ',')) address = address[0..^1]; - address = address.ToUpperInvariant(); - var addressed = - address == CommonMention.ToUpperInvariant() - || address == provider.BotMention.ToUpperInvariant(); + address.Equals(CommonMention, StringComparison.OrdinalIgnoreCase) + || address.Equals(provider.BotMention, StringComparison.OrdinalIgnoreCase); // no mention if (!addressed && !message.User.Channel.IsPrivateChannel) @@ -1034,7 +1032,7 @@ ValueTask SendMessage(IEnumerable channelIds, Message? replyTo, MessageCo message.Embed != null ? " (with embed)" : String.Empty, String.Join(", ", channelIdsList)); - if (!channelIdsList.Any()) + if (channelIdsList.Count == 0) return ValueTask.CompletedTask; return ValueTaskExtensions.WhenAll( From 02e5e86f21113061acd26160d50c7c9d019ba6ff Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 22:49:38 -0500 Subject: [PATCH 536/717] Nullify `User` --- .../Controllers/ApiRootController.cs | 4 ++-- .../Jobs/JobsHubGroupMapper.cs | 2 +- src/Tgstation.Server.Host/Models/User.cs | 18 ++++++++---------- .../Security/AuthenticationContext.cs | 2 +- .../Security/AuthenticationContextFactory.cs | 4 ++-- .../Security/CryptographySuite.cs | 3 +++ 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ApiRootController.cs b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs index 334eba85a42..5248d3f3138 100644 --- a/src/Tgstation.Server.Host/Controllers/ApiRootController.cs +++ b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs @@ -263,13 +263,13 @@ public async ValueTask CreateToken(CancellationToken cancellation return Unauthorized(); query = query.Where( - x => x.OAuthConnections.Any( + x => x.OAuthConnections!.Any( y => y.Provider == oAuthProvider && y.ExternalUserId == externalUserId)); } else { - var canonicalUserName = Models.User.CanonicalizeName(ApiHeaders.Username); + var canonicalUserName = Models.User.CanonicalizeName(ApiHeaders.Username!); if (canonicalUserName == Models.User.CanonicalizeName(Models.User.TgsSystemUserName)) return Unauthorized(); diff --git a/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs b/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs index 6264c185d78..a961fbaef99 100644 --- a/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs +++ b/src/Tgstation.Server.Host/Jobs/JobsHubGroupMapper.cs @@ -153,7 +153,7 @@ ValueTask RefreshHubGroups(long permissionSetId, CancellationToken cancellationT logger.LogTrace("RefreshHubGroups"); var permissionSetUsers = await databaseContext .Users - .Where(x => x.PermissionSet.Id == permissionSetId) + .Where(x => x.PermissionSet!.Id == permissionSetId) .ToListAsync(cancellationToken); var allInstanceIds = await databaseContext .Instances diff --git a/src/Tgstation.Server.Host/Models/User.cs b/src/Tgstation.Server.Host/Models/User.cs index 4c4e2c03b03..0939dd8042c 100644 --- a/src/Tgstation.Server.Host/Models/User.cs +++ b/src/Tgstation.Server.Host/Models/User.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -21,17 +19,17 @@ public sealed class User : Api.Models.Internal.UserModelBase, IApiTransformable< /// /// The hash of the user's password. /// - public string PasswordHash { get; set; } + public string? PasswordHash { get; set; } /// /// See . /// - public User CreatedBy { get; set; } + public User? CreatedBy { get; set; } /// /// The the belongs to, if any. /// - public UserGroup Group { get; set; } + public UserGroup? Group { get; set; } /// /// The ID of the 's . @@ -41,14 +39,14 @@ public sealed class User : Api.Models.Internal.UserModelBase, IApiTransformable< /// /// The the has, if any. /// - public PermissionSet PermissionSet { get; set; } + public PermissionSet? PermissionSet { get; set; } /// /// The uppercase invariant of . /// [Required] [StringLength(Limits.MaximumIndexableStringLength, MinimumLength = 1)] - public string CanonicalName { get; set; } + public string? CanonicalName { get; set; } /// /// When was last changed. @@ -58,17 +56,17 @@ public sealed class User : Api.Models.Internal.UserModelBase, IApiTransformable< /// /// s created by this . /// - public ICollection CreatedUsers { get; set; } + public ICollection? CreatedUsers { get; set; } /// /// The s made by the . /// - public ICollection TestMerges { get; set; } + public ICollection? TestMerges { get; set; } /// /// The s made by the . /// - public ICollection OAuthConnections { get; set; } + public ICollection? OAuthConnections { get; set; } /// /// Change a into a . diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContext.cs b/src/Tgstation.Server.Host/Security/AuthenticationContext.cs index c40d122743e..61c6c36f440 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContext.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContext.cs @@ -56,7 +56,7 @@ public void Initialize(ISystemIdentity? systemIdentity, User user, InstancePermi if (systemIdentity == null && User.SystemIdentifier != null) throw new ArgumentNullException(nameof(systemIdentity)); permissionSet = user.PermissionSet - ?? user.Group.PermissionSet + ?? user.Group!.PermissionSet ?? throw new ArgumentException("No PermissionSet provider", nameof(user)); InstancePermissionSet = instanceUser; SystemIdentity = systemIdentity; diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs b/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs index 7fa7b2802f8..ad9ecf014fc 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs @@ -88,7 +88,7 @@ public async ValueTask CreateAuthenticationContext(long .Include(x => x.CreatedBy) .Include(x => x.PermissionSet) .Include(x => x.Group) - .ThenInclude(x => x.PermissionSet) + .ThenInclude(x => x!.PermissionSet) .Include(x => x.OAuthConnections) .FirstOrDefaultAsync(cancellationToken); if (user == default) @@ -111,7 +111,7 @@ public async ValueTask CreateAuthenticationContext(long systemIdentity = null; } - var userPermissionSet = user.PermissionSet ?? user.Group.PermissionSet; + var userPermissionSet = user.PermissionSet ?? user.Group!.PermissionSet; try { InstancePermissionSet? instancePermissionSet = null; diff --git a/src/Tgstation.Server.Host/Security/CryptographySuite.cs b/src/Tgstation.Server.Host/Security/CryptographySuite.cs index d98e61c303f..6a401e75751 100644 --- a/src/Tgstation.Server.Host/Security/CryptographySuite.cs +++ b/src/Tgstation.Server.Host/Security/CryptographySuite.cs @@ -55,6 +55,9 @@ public bool CheckUserPassword(User user, string password) ArgumentNullException.ThrowIfNull(user); ArgumentNullException.ThrowIfNull(password); + if (user.PasswordHash == null) + throw new ArgumentException("user must have PasswordHash!", nameof(user)); + var result = passwordHasher.VerifyHashedPassword(user, user.PasswordHash, password); switch (result) { From 3f0a5d0323e1f8c69bd2f9a0f3b4d0b621fed499 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 22:50:54 -0500 Subject: [PATCH 537/717] Nullify `UserGroup` --- src/Tgstation.Server.Host/Models/UserGroup.cs | 11 +++++------ .../Security/AuthenticationContextFactory.cs | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Models/UserGroup.cs b/src/Tgstation.Server.Host/Models/UserGroup.cs index 65c18474fac..4451c1a0732 100644 --- a/src/Tgstation.Server.Host/Models/UserGroup.cs +++ b/src/Tgstation.Server.Host/Models/UserGroup.cs @@ -1,12 +1,11 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Response; -#nullable disable - namespace Tgstation.Server.Host.Models { /// @@ -18,12 +17,12 @@ public sealed class UserGroup : NamedEntity, IApiTransformable the has. /// [Required] - public PermissionSet PermissionSet { get; set; } + public PermissionSet? PermissionSet { get; set; } /// /// The s the has. /// - public ICollection Users { get; set; } + public ICollection? Users { get; set; } /// /// Convert the to it's API form. @@ -34,7 +33,7 @@ public sealed class UserGroup : NamedEntity, IApiTransformable x.CreateUserName()) diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs b/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs index ad9ecf014fc..80a9f1df920 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs @@ -119,7 +119,7 @@ public async ValueTask CreateAuthenticationContext(long { instancePermissionSet = await databaseContext.InstancePermissionSets .AsQueryable() - .Where(x => x.PermissionSetId == userPermissionSet.Id && x.InstanceId == instanceId && x.Instance!.SwarmIdentifer == swarmConfiguration.Identifier) + .Where(x => x.PermissionSetId == userPermissionSet!.Id && x.InstanceId == instanceId && x.Instance!.SwarmIdentifer == swarmConfiguration.Identifier) .Include(x => x.Instance) .FirstOrDefaultAsync(cancellationToken); From 0159792cfe8649a57d96c4cb10750099342d88cd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 22:52:06 -0500 Subject: [PATCH 538/717] Remove an unused field --- .../Controllers/ApiRootController.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ApiRootController.cs b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs index 5248d3f3138..061869345f4 100644 --- a/src/Tgstation.Server.Host/Controllers/ApiRootController.cs +++ b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs @@ -85,11 +85,6 @@ public sealed class ApiRootController : ApiController /// readonly GeneralConfiguration generalConfiguration; - /// - /// The for the . - /// - readonly ControlPanelConfiguration controlPanelConfiguration; - /// /// Initializes a new instance of the class. /// @@ -105,7 +100,6 @@ public sealed class ApiRootController : ApiController /// The value of . /// The value of . /// The containing the value of . - /// The containing the value of . /// The for the . /// The for the . public ApiRootController( @@ -121,7 +115,6 @@ public ApiRootController( ISwarmService swarmService, IServerControl serverControl, IOptions generalConfigurationOptions, - IOptions controlPanelConfigurationOptions, ILogger logger, IApiHeadersProvider apiHeadersProvider) : base( @@ -141,7 +134,6 @@ public ApiRootController( this.swarmService = swarmService ?? throw new ArgumentNullException(nameof(swarmService)); this.serverControl = serverControl ?? throw new ArgumentNullException(nameof(serverControl)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); - controlPanelConfiguration = controlPanelConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(controlPanelConfigurationOptions)); } /// From 63465d23cddc3c348dc4d24c7cd3ec4949ff77c8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 22:52:34 -0500 Subject: [PATCH 539/717] Cleanup a VS IDE message --- src/Tgstation.Server.Host/Controllers/ApiRootController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Controllers/ApiRootController.cs b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs index 061869345f4..fa6b3e0c4b6 100644 --- a/src/Tgstation.Server.Host/Controllers/ApiRootController.cs +++ b/src/Tgstation.Server.Host/Controllers/ApiRootController.cs @@ -162,7 +162,7 @@ public IActionResult ServerInfo() return HeadersIssue(ex); } - failIfUnauthed = Request.Headers.Authorization.Any(); + failIfUnauthed = Request.Headers.Authorization.Count > 0; } else failIfUnauthed = ApiHeaders.Token != null; From d0bf6eb086822ab74cb08c9644b8a2977b53c0ba Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 18 Dec 2023 22:53:04 -0500 Subject: [PATCH 540/717] Simplify a null check --- src/Tgstation.Server.Host/Security/AuthenticationContext.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContext.cs b/src/Tgstation.Server.Host/Security/AuthenticationContext.cs index 61c6c36f440..53bf23c2a21 100644 --- a/src/Tgstation.Server.Host/Security/AuthenticationContext.cs +++ b/src/Tgstation.Server.Host/Security/AuthenticationContext.cs @@ -88,10 +88,8 @@ public ulong GetRight(RightsType rightsType) isInstance ? InstancePermissionSet : PermissionSet, - Array.Empty()); - - if (right == null) - throw new InvalidOperationException("A user right was null!"); + Array.Empty()) + ?? throw new InvalidOperationException("A user right was null!"); return (ulong)right; } From b06be253decdfade9f72b14dcbf90f9a78ec2621 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 19 Dec 2023 09:20:01 -0500 Subject: [PATCH 541/717] Nullify `IRestartRegistration` --- src/Tgstation.Server.Host/Core/IRestartRegistration.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Core/IRestartRegistration.cs b/src/Tgstation.Server.Host/Core/IRestartRegistration.cs index ee2ddc7ddfa..586d73f0047 100644 --- a/src/Tgstation.Server.Host/Core/IRestartRegistration.cs +++ b/src/Tgstation.Server.Host/Core/IRestartRegistration.cs @@ -1,7 +1,5 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.Core { /// From d58ef02d31a7b5332eb614752f2d18d55e464004 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 19 Dec 2023 22:24:32 -0500 Subject: [PATCH 542/717] This property is meant to be nullable --- .../Components/Deployment/DreamMaker.cs | 3 ++- src/Tgstation.Server.Host/Models/CompileJob.cs | 16 ++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index 255c07dd543..89f69f7d7b0 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -488,10 +488,11 @@ await databaseContextFactory.UseContext( repository.RemoteRepositoryName, localCommitExistsOnRemote); - var compileJob = new Models.CompileJob(job, revisionInformation, engineLock.Version.ToString(), repository.Origin.ToString()) + var compileJob = new Models.CompileJob(job, revisionInformation, engineLock.Version.ToString()) { DirectoryName = Guid.NewGuid(), DmeName = dreamMakerSettings.ProjectName, + RepositoryOrigin = repository.Origin.ToString(), }; progressReporter.StageName = "Creating remote deployment notification"; diff --git a/src/Tgstation.Server.Host/Models/CompileJob.cs b/src/Tgstation.Server.Host/Models/CompileJob.cs index ea729e9217d..0f75b830e70 100644 --- a/src/Tgstation.Server.Host/Models/CompileJob.cs +++ b/src/Tgstation.Server.Host/Models/CompileJob.cs @@ -50,7 +50,7 @@ public sealed class CompileJob : Api.Models.Internal.CompileJob, IApiTransformab /// /// The origin of the repository the compile job was built from. /// - public string RepositoryOrigin { get; set; } + public string? RepositoryOrigin { get; set; } /// /// The source GitHub repository the deployment came from if any. @@ -86,7 +86,7 @@ public override Version? DMApiVersion /// [Obsolete("For use by EFCore only", true)] public CompileJob() - : this(null!, null!, null!, null!, false) + : this(null!, null!, null!, false) { } @@ -96,9 +96,8 @@ public CompileJob() /// The value of . /// The value of . /// The value of . - /// The value of . - public CompileJob(Job job, RevisionInformation revisionInformation, string engineVersion, string repositoryOrigin) - : this(job, revisionInformation, engineVersion, repositoryOrigin, true) + public CompileJob(Job job, RevisionInformation revisionInformation, string engineVersion) + : this(job, revisionInformation, engineVersion, true) { } @@ -108,22 +107,19 @@ public CompileJob(Job job, RevisionInformation revisionInformation, string engin /// The value of . /// The value of . /// The value of . - /// The value of . - /// If , , and should be checked for nulls. - CompileJob(Job job, RevisionInformation revisionInformation, string engineVersion, string repositoryOrigin, bool nullChecks) + /// If , , and should be checked for nulls. + CompileJob(Job job, RevisionInformation revisionInformation, string engineVersion, bool nullChecks) { if (nullChecks) { ArgumentNullException.ThrowIfNull(job); ArgumentNullException.ThrowIfNull(revisionInformation); ArgumentNullException.ThrowIfNull(engineVersion); - ArgumentNullException.ThrowIfNull(repositoryOrigin); } Job = job; RevisionInformation = revisionInformation; EngineVersion = engineVersion; - RepositoryOrigin = repositoryOrigin; } /// From 0df55f772ba0024ade9d695f5786921e6a63084b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 19 Dec 2023 23:12:52 -0500 Subject: [PATCH 543/717] Add separate database field for topic port --- .../Components/Session/SessionController.cs | 6 +- .../Database/DatabaseContext.cs | 8 +- .../20231220032508_MSAddTopicPort.Designer.cs | 1076 ++++++++++++++++ .../20231220032508_MSAddTopicPort.cs | 32 + .../20231220032515_MYAddTopicPort.Designer.cs | 1110 +++++++++++++++++ .../20231220032515_MYAddTopicPort.cs | 32 + .../20231220032521_PGAddTopicPort.Designer.cs | 1070 ++++++++++++++++ .../20231220032521_PGAddTopicPort.cs | 32 + .../20231220032528_SLAddTopicPort.Designer.cs | 1042 ++++++++++++++++ .../20231220032528_SLAddTopicPort.cs | 32 + .../MySqlDatabaseContextModelSnapshot.cs | 20 +- ...PostgresSqlDatabaseContextModelSnapshot.cs | 18 +- .../SqlServerDatabaseContextModelSnapshot.cs | 18 +- .../SqliteDatabaseContextModelSnapshot.cs | 16 +- .../Models/ReattachInformationBase.cs | 8 +- 15 files changed, 4480 insertions(+), 40 deletions(-) create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231220032508_MSAddTopicPort.Designer.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231220032508_MSAddTopicPort.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231220032515_MYAddTopicPort.Designer.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231220032515_MYAddTopicPort.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231220032521_PGAddTopicPort.Designer.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231220032521_PGAddTopicPort.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231220032528_SLAddTopicPort.Designer.cs create mode 100644 src/Tgstation.Server.Host/Database/Migrations/20231220032528_SLAddTopicPort.cs diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 5a5c5d909c4..56ef1416c2e 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -679,7 +679,7 @@ async ValueTask ProcessBridgeCommand(BridgeParameters parameters { var newTopicPort = parameters.TopicPort.Value; Logger.LogInformation("Server is requesting use of port {topicPort} for topic communications", newTopicPort); - ReattachInformation.Port = newTopicPort; + ReattachInformation.TopicPort = newTopicPort; } // Load custom commands @@ -885,7 +885,7 @@ async ValueTask SendRawTopic(string queryString, bool pri return null; } - var targetPort = ReattachInformation.Port; + var targetPort = ReattachInformation.TopicPort ?? ReattachInformation.Port; Byond.TopicSender.TopicResponse byondResponse; using (await TopicSendSemaphore.Lock(cancellationToken)) byondResponse = await byondTopicSender.SendWithOptionalPriority( diff --git a/src/Tgstation.Server.Host/Database/DatabaseContext.cs b/src/Tgstation.Server.Host/Database/DatabaseContext.cs index ec2095d2740..978a73076bc 100644 --- a/src/Tgstation.Server.Host/Database/DatabaseContext.cs +++ b/src/Tgstation.Server.Host/Database/DatabaseContext.cs @@ -375,22 +375,22 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) /// /// Used by unit tests to remind us to setup the correct MSSQL migration downgrades. /// - internal static readonly Type MSLatestMigration = typeof(MSRenameByondColumnsToEngine); + internal static readonly Type MSLatestMigration = typeof(MSAddTopicPort); /// /// Used by unit tests to remind us to setup the correct MYSQL migration downgrades. /// - internal static readonly Type MYLatestMigration = typeof(MYRenameByondColumnsToEngine); + internal static readonly Type MYLatestMigration = typeof(MYAddTopicPort); /// /// Used by unit tests to remind us to setup the correct PostgresSQL migration downgrades. /// - internal static readonly Type PGLatestMigration = typeof(PGRenameByondColumnsToEngine); + internal static readonly Type PGLatestMigration = typeof(PGAddTopicPort); /// /// Used by unit tests to remind us to setup the correct SQLite migration downgrades. /// - internal static readonly Type SLLatestMigration = typeof(SLRenameByondColumnsToEngine); + internal static readonly Type SLLatestMigration = typeof(SLAddTopicPort); /// #pragma warning disable CA1502 // Cyclomatic complexity diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231220032508_MSAddTopicPort.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231220032508_MSAddTopicPort.Designer.cs new file mode 100644 index 00000000000..39d9629c7c8 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231220032508_MSAddTopicPort.Designer.cs @@ -0,0 +1,1076 @@ +// +using System; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(SqlServerDatabaseContext))] + [Migration("20231220032508_MSAddTopicPort")] + partial class MSAddTopicPort + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChannelLimit") + .HasColumnType("int"); + + b.Property("ConnectionString") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChatSettingsId") + .HasColumnType("bigint"); + + b.Property("DiscordChannelId") + .HasColumnType("decimal(20,0)"); + + b.Property("IrcChannel") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("IsSystemChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("bit"); + + b.Property("Tag") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + 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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + 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("EngineVersion") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("GitHubDeploymentId") + .HasColumnType("int"); + + b.Property("GitHubRepoId") + .HasColumnType("bigint"); + + b.Property("JobId") + .HasColumnType("bigint"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("int"); + + b.Property("Output") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RepositoryOrigin") + .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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AdditionalParameters") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("bit"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("bit"); + + b.Property("DumpOnHealthCheckRestart") + .IsRequired() + .HasColumnType("bit"); + + b.Property("HealthCheckSeconds") + .HasColumnType("bigint"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("LogOutput") + .IsRequired() + .HasColumnType("bit"); + + b.Property("MapThreads") + .HasColumnType("bigint"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("SecurityLevel") + .HasColumnType("int"); + + b.Property("StartProfiler") + .IsRequired() + .HasColumnType("bit"); + + b.Property("StartupTimeout") + .HasColumnType("bigint"); + + b.Property("TopicRequestTimeout") + .HasColumnType("bigint"); + + b.Property("Visibility") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ApiValidationPort") + .HasColumnType("int"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("int"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("ProjectName") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("bit"); + + b.Property("Timeout") + .IsRequired() + .HasColumnType("time"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AutoUpdateInterval") + .HasColumnType("bigint"); + + b.Property("ChatBotLimit") + .HasColumnType("int"); + + b.Property("ConfigurationType") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Online") + .IsRequired() + .HasColumnType("bit"); + + b.Property("Path") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("SwarmIdentifer") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique() + .HasFilter("[SwarmIdentifer] IS NOT NULL"); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + 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("EngineRights") + .HasColumnType("decimal(20,0)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("decimal(20,0)"); + + b.Property("PermissionSetId") + .HasColumnType("bigint"); + + b.Property("RepositoryRights") + .HasColumnType("decimal(20,0)"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.HasIndex("PermissionSetId", "InstanceId") + .IsUnique(); + + b.ToTable("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + 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("JobCode") + .HasColumnType("tinyint"); + + 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.OAuthConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ExternalUserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Provider") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("Provider", "ExternalUserId") + .IsUnique(); + + b.ToTable("OAuthConnections"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AdministrationRights") + .HasColumnType("decimal(20,0)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("InstanceManagerRights") + .HasColumnType("decimal(20,0)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique() + .HasFilter("[GroupId] IS NOT NULL"); + + b.HasIndex("UserId") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompileJobId") + .HasColumnType("bigint"); + + b.Property("InitialCompileJobId") + .HasColumnType("bigint"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("int"); + + b.Property("LaunchVisibility") + .HasColumnType("int"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("ProcessId") + .HasColumnType("int"); + + b.Property("RebootState") + .HasColumnType("int"); + + b.Property("TopicPort") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.HasIndex("InitialCompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccessToken") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("AccessUser") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("bit"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("bit"); + + b.Property("CommitterEmail") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("CommitterName") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("bit"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("bit"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("bit"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("bit"); + + b.Property("UpdateSubmodules") + .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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + 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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("Timestamp") + .HasColumnType("datetimeoffset"); + + 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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Author") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Comment") + .HasMaxLength(10000) + .HasColumnType("nvarchar(max)"); + + b.Property("MergedAt") + .HasColumnType("datetimeoffset"); + + b.Property("MergedById") + .HasColumnType("bigint"); + + b.Property("Number") + .HasColumnType("int"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("bigint"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(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"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CanonicalName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("datetimeoffset"); + + b.Property("CreatedById") + .HasColumnType("bigint"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("bit"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastPasswordUpdate") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("SystemIdentifier") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique() + .HasFilter("[SystemIdentifier] IS NOT NULL"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("ChatSettings") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChatSettings"); + }); + + 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(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("InstancePermissionSets") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet") + .WithMany("InstancePermissionSets") + .HasForeignKey("PermissionSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); + }); + + 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(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "InitialCompileJob") + .WithMany() + .HasForeignKey("InitialCompileJobId"); + + b.Navigation("CompileJob"); + + b.Navigation("InitialCompileJob"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy") + .WithMany("CreatedUsers") + .HasForeignKey("CreatedById"); + + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithMany("Users") + .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231220032508_MSAddTopicPort.cs b/src/Tgstation.Server.Host/Database/Migrations/20231220032508_MSAddTopicPort.cs new file mode 100644 index 00000000000..2c1754e5f1a --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231220032508_MSAddTopicPort.cs @@ -0,0 +1,32 @@ +using System; + +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + public partial class MSAddTopicPort : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.AddColumn( + name: "TopicPort", + table: "ReattachInformations", + type: "int", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.DropColumn( + name: "TopicPort", + table: "ReattachInformations"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231220032515_MYAddTopicPort.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231220032515_MYAddTopicPort.Designer.cs new file mode 100644 index 00000000000..593d5f4db2b --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231220032515_MYAddTopicPort.Designer.cs @@ -0,0 +1,1110 @@ +// +using System; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(MySqlDatabaseContext))] + [Migration("20231220032515_MYAddTopicPort")] + partial class MYAddTopicPort + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .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() + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ConnectionString"), "utf8mb4"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(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") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("IrcChannel"), "utf8mb4"); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("IsSystemChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("Tag") + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Tag"), "utf8mb4"); + + 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("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"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("DmeName"), "utf8mb4"); + + b.Property("EngineVersion") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("EngineVersion"), "utf8mb4"); + + b.Property("GitHubDeploymentId") + .HasColumnType("int"); + + b.Property("GitHubRepoId") + .HasColumnType("bigint"); + + b.Property("JobId") + .HasColumnType("bigint"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("int"); + + b.Property("Output") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Output"), "utf8mb4"); + + b.Property("RepositoryOrigin") + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("RepositoryOrigin"), "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("AdditionalParameters") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("AdditionalParameters"), "utf8mb4"); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("DumpOnHealthCheckRestart") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("HealthCheckSeconds") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("LogOutput") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("MapThreads") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("Port") + .IsRequired() + .HasColumnType("smallint unsigned"); + + b.Property("SecurityLevel") + .HasColumnType("int"); + + b.Property("StartProfiler") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("StartupTimeout") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("TopicRequestTimeout") + .IsRequired() + .HasColumnType("int unsigned"); + + b.Property("Visibility") + .HasColumnType("int"); + + 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") + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ProjectName"), "utf8mb4"); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("Timeout") + .IsRequired() + .HasColumnType("time(6)"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + 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() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Name"), "utf8mb4"); + + b.Property("Online") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("Path") + .IsRequired() + .HasColumnType("varchar(255)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Path"), "utf8mb4"); + + b.Property("SwarmIdentifer") + .HasColumnType("varchar(255)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("SwarmIdentifer"), "utf8mb4"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique(); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + 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("EngineRights") + .HasColumnType("bigint unsigned"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("bigint unsigned"); + + b.Property("PermissionSetId") + .HasColumnType("bigint"); + + b.Property("RepositoryRights") + .HasColumnType("bigint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.HasIndex("PermissionSetId", "InstanceId") + .IsUnique(); + + b.ToTable("InstancePermissionSets"); + }); + + 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"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Description"), "utf8mb4"); + + b.Property("ErrorCode") + .HasColumnType("int unsigned"); + + b.Property("ExceptionDetails") + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ExceptionDetails"), "utf8mb4"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("JobCode") + .HasColumnType("tinyint unsigned"); + + 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.OAuthConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ExternalUserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ExternalUserId"), "utf8mb4"); + + b.Property("Provider") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("Provider", "ExternalUserId") + .IsUnique(); + + b.ToTable("OAuthConnections"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AdministrationRights") + .HasColumnType("bigint unsigned"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("InstanceManagerRights") + .HasColumnType("bigint unsigned"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique(); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("AccessIdentifier"), "utf8mb4"); + + b.Property("CompileJobId") + .HasColumnType("bigint"); + + b.Property("InitialCompileJobId") + .HasColumnType("bigint"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("int"); + + b.Property("LaunchVisibility") + .HasColumnType("int"); + + b.Property("Port") + .HasColumnType("smallint unsigned"); + + b.Property("ProcessId") + .HasColumnType("int"); + + b.Property("RebootState") + .HasColumnType("int"); + + b.Property("TopicPort") + .HasColumnType("smallint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.HasIndex("InitialCompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccessToken") + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("AccessToken"), "utf8mb4"); + + b.Property("AccessUser") + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("AccessUser"), "utf8mb4"); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("CommitterEmail") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("CommitterEmail"), "utf8mb4"); + + b.Property("CommitterName") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("CommitterName"), "utf8mb4"); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("tinyint(1)"); + + 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.Property("UpdateSubmodules") + .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() + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("CommitSha"), "utf8mb4"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("OriginCommitSha"), "utf8mb4"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + 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("Author") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Author"), "utf8mb4"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("BodyAtMerge"), "utf8mb4"); + + b.Property("Comment") + .HasMaxLength(10000) + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Comment"), "utf8mb4"); + + b.Property("MergedAt") + .HasColumnType("datetime(6)"); + + b.Property("MergedById") + .HasColumnType("bigint"); + + b.Property("Number") + .HasColumnType("int"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("bigint"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("TargetCommitSha"), "utf8mb4"); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("TitleAtMerge"), "utf8mb4"); + + b.Property("Url") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Url"), "utf8mb4"); + + 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"); + + b.Property("CanonicalName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("CanonicalName"), "utf8mb4"); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("bigint"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("tinyint(1)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastPasswordUpdate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Name"), "utf8mb4"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("PasswordHash"), "utf8mb4"); + + b.Property("SystemIdentifier") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("SystemIdentifier"), "utf8mb4"); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("Name"), "utf8mb4"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("ChatSettings") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChatSettings"); + }); + + 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.Cascade) + .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("InstancePermissionSets") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet") + .WithMany("InstancePermissionSets") + .HasForeignKey("PermissionSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); + }); + + 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(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "InitialCompileJob") + .WithMany() + .HasForeignKey("InitialCompileJobId"); + + b.Navigation("CompileJob"); + + b.Navigation("InitialCompileJob"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy") + .WithMany("CreatedUsers") + .HasForeignKey("CreatedById"); + + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithMany("Users") + .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231220032515_MYAddTopicPort.cs b/src/Tgstation.Server.Host/Database/Migrations/20231220032515_MYAddTopicPort.cs new file mode 100644 index 00000000000..1630786ccf5 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231220032515_MYAddTopicPort.cs @@ -0,0 +1,32 @@ +using System; + +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + public partial class MYAddTopicPort : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.AddColumn( + name: "TopicPort", + table: "ReattachInformations", + type: "smallint unsigned", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.DropColumn( + name: "TopicPort", + table: "ReattachInformations"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231220032521_PGAddTopicPort.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231220032521_PGAddTopicPort.Designer.cs new file mode 100644 index 00000000000..6f31c5e109d --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231220032521_PGAddTopicPort.Designer.cs @@ -0,0 +1,1070 @@ +// +using System; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(PostgresSqlDatabaseContext))] + [Migration("20231220032521_PGAddTopicPort")] + partial class PGAddTopicPort + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelLimit") + .HasColumnType("integer"); + + b.Property("ConnectionString") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Provider") + .HasColumnType("integer"); + + 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"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChatSettingsId") + .HasColumnType("bigint"); + + b.Property("DiscordChannelId") + .HasColumnType("numeric(20,0)"); + + b.Property("IrcChannel") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("IsSystemChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("Tag") + .HasMaxLength(10000) + .HasColumnType("character varying(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"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DMApiMajorVersion") + .HasColumnType("integer"); + + b.Property("DMApiMinorVersion") + .HasColumnType("integer"); + + b.Property("DMApiPatchVersion") + .HasColumnType("integer"); + + b.Property("DirectoryName") + .IsRequired() + .HasColumnType("uuid"); + + b.Property("DmeName") + .IsRequired() + .HasColumnType("text"); + + b.Property("EngineVersion") + .IsRequired() + .HasColumnType("text"); + + b.Property("GitHubDeploymentId") + .HasColumnType("integer"); + + b.Property("GitHubRepoId") + .HasColumnType("bigint"); + + b.Property("JobId") + .HasColumnType("bigint"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("integer"); + + b.Property("Output") + .IsRequired() + .HasColumnType("text"); + + b.Property("RepositoryOrigin") + .HasColumnType("text"); + + 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"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AdditionalParameters") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("DumpOnHealthCheckRestart") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("HealthCheckSeconds") + .HasColumnType("bigint"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("LogOutput") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("MapThreads") + .HasColumnType("bigint"); + + b.Property("Port") + .HasColumnType("integer"); + + b.Property("SecurityLevel") + .HasColumnType("integer"); + + b.Property("StartProfiler") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("StartupTimeout") + .HasColumnType("bigint"); + + b.Property("TopicRequestTimeout") + .HasColumnType("bigint"); + + b.Property("Visibility") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ApiValidationPort") + .HasColumnType("integer"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("integer"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("ProjectName") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("Timeout") + .IsRequired() + .HasColumnType("interval"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AutoUpdateInterval") + .HasColumnType("bigint"); + + b.Property("ChatBotLimit") + .HasColumnType("integer"); + + b.Property("ConfigurationType") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Online") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("SwarmIdentifer") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique(); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChatBotRights") + .HasColumnType("numeric(20,0)"); + + b.Property("ConfigurationRights") + .HasColumnType("numeric(20,0)"); + + b.Property("DreamDaemonRights") + .HasColumnType("numeric(20,0)"); + + b.Property("DreamMakerRights") + .HasColumnType("numeric(20,0)"); + + b.Property("EngineRights") + .HasColumnType("numeric(20,0)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("numeric(20,0)"); + + b.Property("PermissionSetId") + .HasColumnType("bigint"); + + b.Property("RepositoryRights") + .HasColumnType("numeric(20,0)"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.HasIndex("PermissionSetId", "InstanceId") + .IsUnique(); + + b.ToTable("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CancelRight") + .HasColumnType("numeric(20,0)"); + + b.Property("CancelRightsType") + .HasColumnType("numeric(20,0)"); + + b.Property("Cancelled") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("CancelledById") + .HasColumnType("bigint"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ErrorCode") + .HasColumnType("bigint"); + + b.Property("ExceptionDetails") + .HasColumnType("text"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("JobCode") + .HasColumnType("smallint"); + + b.Property("StartedAt") + .IsRequired() + .HasColumnType("timestamp with time zone"); + + b.Property("StartedById") + .HasColumnType("bigint"); + + b.Property("StoppedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CancelledById"); + + b.HasIndex("InstanceId"); + + b.HasIndex("StartedById"); + + b.ToTable("Jobs"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ExternalUserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Provider") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("Provider", "ExternalUserId") + .IsUnique(); + + b.ToTable("OAuthConnections"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AdministrationRights") + .HasColumnType("numeric(20,0)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("InstanceManagerRights") + .HasColumnType("numeric(20,0)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique(); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("text"); + + b.Property("CompileJobId") + .HasColumnType("bigint"); + + b.Property("InitialCompileJobId") + .HasColumnType("bigint"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("integer"); + + b.Property("LaunchVisibility") + .HasColumnType("integer"); + + b.Property("Port") + .HasColumnType("integer"); + + b.Property("ProcessId") + .HasColumnType("integer"); + + b.Property("RebootState") + .HasColumnType("integer"); + + b.Property("TopicPort") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.HasIndex("InitialCompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessToken") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("AccessUser") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("CommitterEmail") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("CommitterName") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("UpdateSubmodules") + .IsRequired() + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("RepositorySettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + 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"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("InstanceId") + .HasColumnType("bigint"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + 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"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Author") + .IsRequired() + .HasColumnType("text"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Comment") + .HasMaxLength(10000) + .HasColumnType("character varying(10000)"); + + b.Property("MergedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MergedById") + .HasColumnType("bigint"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("bigint"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("text"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text"); + + 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"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CanonicalName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedById") + .HasColumnType("bigint"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("boolean"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastPasswordUpdate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("SystemIdentifier") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("ChatSettings") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChatSettings"); + }); + + 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.Cascade) + .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("InstancePermissionSets") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet") + .WithMany("InstancePermissionSets") + .HasForeignKey("PermissionSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); + }); + + 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(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "InitialCompileJob") + .WithMany() + .HasForeignKey("InitialCompileJobId"); + + b.Navigation("CompileJob"); + + b.Navigation("InitialCompileJob"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy") + .WithMany("CreatedUsers") + .HasForeignKey("CreatedById"); + + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithMany("Users") + .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231220032521_PGAddTopicPort.cs b/src/Tgstation.Server.Host/Database/Migrations/20231220032521_PGAddTopicPort.cs new file mode 100644 index 00000000000..1994a0b3f90 --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231220032521_PGAddTopicPort.cs @@ -0,0 +1,32 @@ +using System; + +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + public partial class PGAddTopicPort : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.AddColumn( + name: "TopicPort", + table: "ReattachInformations", + type: "integer", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.DropColumn( + name: "TopicPort", + table: "ReattachInformations"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231220032528_SLAddTopicPort.Designer.cs b/src/Tgstation.Server.Host/Database/Migrations/20231220032528_SLAddTopicPort.Designer.cs new file mode 100644 index 00000000000..1352af4855c --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231220032528_SLAddTopicPort.Designer.cs @@ -0,0 +1,1042 @@ +// +using System; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + [DbContext(typeof(SqliteDatabaseContext))] + [Migration("20231220032528_SLAddTopicPort")] + partial class SLAddTopicPort + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.0"); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelLimit") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ConnectionString") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.Property("ReconnectionInterval") + .IsRequired() + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "Name") + .IsUnique(); + + b.ToTable("ChatBots"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChatSettingsId") + .HasColumnType("INTEGER"); + + b.Property("DiscordChannelId") + .HasColumnType("INTEGER"); + + b.Property("IrcChannel") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("IsAdminChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("IsSystemChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("IsUpdatesChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("IsWatchdogChannel") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Tag") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + 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("INTEGER"); + + b.Property("DMApiMajorVersion") + .HasColumnType("INTEGER"); + + b.Property("DMApiMinorVersion") + .HasColumnType("INTEGER"); + + b.Property("DMApiPatchVersion") + .HasColumnType("INTEGER"); + + b.Property("DirectoryName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DmeName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("EngineVersion") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("GitHubDeploymentId") + .HasColumnType("INTEGER"); + + b.Property("GitHubRepoId") + .HasColumnType("INTEGER"); + + b.Property("JobId") + .HasColumnType("INTEGER"); + + b.Property("MinimumSecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("Output") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RepositoryOrigin") + .HasColumnType("TEXT"); + + b.Property("RevisionInformationId") + .HasColumnType("INTEGER"); + + 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("INTEGER"); + + b.Property("AdditionalParameters") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("AllowWebClient") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("AutoStart") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("DumpOnHealthCheckRestart") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("HealthCheckSeconds") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("LogOutput") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("MapThreads") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Port") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("SecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("StartProfiler") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("StartupTimeout") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("TopicRequestTimeout") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Visibility") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamDaemonSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.DreamMakerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ApiValidationPort") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ApiValidationSecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("ProjectName") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("RequireDMApiValidation") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Timeout") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DreamMakerSettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoUpdateInterval") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ChatBotLimit") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ConfigurationType") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Online") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("SwarmIdentifer") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Path", "SwarmIdentifer") + .IsUnique(); + + b.ToTable("Instances"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChatBotRights") + .HasColumnType("INTEGER"); + + b.Property("ConfigurationRights") + .HasColumnType("INTEGER"); + + b.Property("DreamDaemonRights") + .HasColumnType("INTEGER"); + + b.Property("DreamMakerRights") + .HasColumnType("INTEGER"); + + b.Property("EngineRights") + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("InstancePermissionSetRights") + .HasColumnType("INTEGER"); + + b.Property("PermissionSetId") + .HasColumnType("INTEGER"); + + b.Property("RepositoryRights") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId"); + + b.HasIndex("PermissionSetId", "InstanceId") + .IsUnique(); + + b.ToTable("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CancelRight") + .HasColumnType("INTEGER"); + + b.Property("CancelRightsType") + .HasColumnType("INTEGER"); + + b.Property("Cancelled") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("CancelledById") + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ErrorCode") + .HasColumnType("INTEGER"); + + b.Property("ExceptionDetails") + .HasColumnType("TEXT"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("JobCode") + .HasColumnType("INTEGER"); + + b.Property("StartedAt") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StartedById") + .HasColumnType("INTEGER"); + + b.Property("StoppedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CancelledById"); + + b.HasIndex("InstanceId"); + + b.HasIndex("StartedById"); + + b.ToTable("Jobs"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalUserId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("Provider", "ExternalUserId") + .IsUnique(); + + b.ToTable("OAuthConnections"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AdministrationRights") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.Property("InstanceManagerRights") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GroupId") + .IsUnique(); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessIdentifier") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CompileJobId") + .HasColumnType("INTEGER"); + + b.Property("InitialCompileJobId") + .HasColumnType("INTEGER"); + + b.Property("LaunchSecurityLevel") + .HasColumnType("INTEGER"); + + b.Property("LaunchVisibility") + .HasColumnType("INTEGER"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("ProcessId") + .HasColumnType("INTEGER"); + + b.Property("RebootState") + .HasColumnType("INTEGER"); + + b.Property("TopicPort") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("CompileJobId"); + + b.HasIndex("InitialCompileJobId"); + + b.ToTable("ReattachInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RepositorySettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("AccessUser") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("AutoUpdatesKeepTestMerges") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("AutoUpdatesSynchronize") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("CommitterEmail") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("CommitterName") + .IsRequired() + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("CreateGitHubDeployments") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("PostTestMergeComment") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("PushTestMergeCommits") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("ShowTestMergeCommitters") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("UpdateSubmodules") + .IsRequired() + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("RepositorySettings"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevInfoTestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RevisionInformationId") + .HasColumnType("INTEGER"); + + b.Property("TestMergeId") + .HasColumnType("INTEGER"); + + 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("INTEGER"); + + b.Property("CommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("InstanceId") + .HasColumnType("INTEGER"); + + b.Property("OriginCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("InstanceId", "CommitSha") + .IsUnique(); + + b.ToTable("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Author") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("BodyAtMerge") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Comment") + .HasMaxLength(10000) + .HasColumnType("TEXT"); + + b.Property("MergedAt") + .HasColumnType("TEXT"); + + b.Property("MergedById") + .HasColumnType("INTEGER"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("PrimaryRevisionInformationId") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("TargetCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("TitleAtMerge") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + 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("INTEGER"); + + b.Property("CanonicalName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Enabled") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("INTEGER"); + + b.Property("LastPasswordUpdate") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("SystemIdentifier") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CanonicalName") + .IsUnique(); + + b.HasIndex("CreatedById"); + + b.HasIndex("GroupId"); + + b.HasIndex("SystemIdentifier") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("ChatSettings") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatChannel", b => + { + b.HasOne("Tgstation.Server.Host.Models.ChatBot", "ChatSettings") + .WithMany("Channels") + .HasForeignKey("ChatSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChatSettings"); + }); + + 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(); + + b.Navigation("Job"); + + b.Navigation("RevisionInformation"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.InstancePermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("InstancePermissionSets") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.PermissionSet", "PermissionSet") + .WithMany("InstancePermissionSets") + .HasForeignKey("PermissionSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + + b.Navigation("PermissionSet"); + }); + + 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(); + + b.Navigation("CancelledBy"); + + b.Navigation("Instance"); + + b.Navigation("StartedBy"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.OAuthConnection", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithMany("OAuthConnections") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "GroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Tgstation.Server.Host.Models.User", "User") + .WithOne("PermissionSet") + .HasForeignKey("Tgstation.Server.Host.Models.PermissionSet", "UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "CompileJob") + .WithMany() + .HasForeignKey("CompileJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Tgstation.Server.Host.Models.CompileJob", "InitialCompileJob") + .WithMany() + .HasForeignKey("InitialCompileJobId"); + + b.Navigation("CompileJob"); + + b.Navigation("InitialCompileJob"); + }); + + 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(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("RevisionInformation"); + + b.Navigation("TestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.HasOne("Tgstation.Server.Host.Models.Instance", "Instance") + .WithMany("RevisionInformations") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Instance"); + }); + + 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(); + + b.Navigation("MergedBy"); + + b.Navigation("PrimaryRevisionInformation"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.HasOne("Tgstation.Server.Host.Models.User", "CreatedBy") + .WithMany("CreatedUsers") + .HasForeignKey("CreatedById"); + + b.HasOne("Tgstation.Server.Host.Models.UserGroup", "Group") + .WithMany("Users") + .HasForeignKey("GroupId"); + + b.Navigation("CreatedBy"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => + { + b.Navigation("Channels"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.Instance", b => + { + b.Navigation("ChatSettings"); + + b.Navigation("DreamDaemonSettings"); + + b.Navigation("DreamMakerSettings"); + + b.Navigation("InstancePermissionSets"); + + b.Navigation("Jobs"); + + b.Navigation("RepositorySettings"); + + b.Navigation("RevisionInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.PermissionSet", b => + { + b.Navigation("InstancePermissionSets"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.RevisionInformation", b => + { + b.Navigation("ActiveTestMerges"); + + b.Navigation("CompileJobs"); + + b.Navigation("PrimaryTestMerge"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.TestMerge", b => + { + b.Navigation("RevisonInformations"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.User", b => + { + b.Navigation("CreatedUsers"); + + b.Navigation("OAuthConnections"); + + b.Navigation("PermissionSet"); + + b.Navigation("TestMerges"); + }); + + modelBuilder.Entity("Tgstation.Server.Host.Models.UserGroup", b => + { + b.Navigation("PermissionSet") + .IsRequired(); + + b.Navigation("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/20231220032528_SLAddTopicPort.cs b/src/Tgstation.Server.Host/Database/Migrations/20231220032528_SLAddTopicPort.cs new file mode 100644 index 00000000000..7ea822bd2ac --- /dev/null +++ b/src/Tgstation.Server.Host/Database/Migrations/20231220032528_SLAddTopicPort.cs @@ -0,0 +1,32 @@ +using System; + +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tgstation.Server.Host.Database.Migrations +{ + /// + public partial class SLAddTopicPort : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.AddColumn( + name: "TopicPort", + table: "ReattachInformations", + type: "INTEGER", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + ArgumentNullException.ThrowIfNull(migrationBuilder); + + migrationBuilder.DropColumn( + name: "TopicPort", + table: "ReattachInformations"); + } + } +} diff --git a/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs index e470e52b3cf..1f42bd3856b 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/MySqlDatabaseContextModelSnapshot.cs @@ -13,7 +13,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6") + .HasAnnotation("ProductVersion", "8.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => @@ -116,13 +116,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("bigint"); - b.Property("ByondVersion") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("EngineVersion"); - - MySqlPropertyBuilderExtensions.HasCharSet(b.Property("ByondVersion"), "utf8mb4"); - b.Property("DMApiMajorVersion") .HasColumnType("int"); @@ -142,6 +135,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) MySqlPropertyBuilderExtensions.HasCharSet(b.Property("DmeName"), "utf8mb4"); + b.Property("EngineVersion") + .IsRequired() + .HasColumnType("longtext"); + + MySqlPropertyBuilderExtensions.HasCharSet(b.Property("EngineVersion"), "utf8mb4"); + b.Property("GitHubDeploymentId") .HasColumnType("int"); @@ -498,7 +497,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => { - b.Property("Id") + b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); @@ -529,6 +528,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("RebootState") .HasColumnType("int"); + b.Property("TopicPort") + .HasColumnType("smallint unsigned"); + b.HasKey("Id"); b.HasIndex("CompileJobId"); diff --git a/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs index 96f60f68507..631cf53bc9d 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/PostgresSqlDatabaseContextModelSnapshot.cs @@ -13,7 +13,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6") + .HasAnnotation("ProductVersion", "8.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -116,11 +116,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("ByondVersion") - .IsRequired() - .HasColumnType("text") - .HasColumnName("EngineVersion"); - b.Property("DMApiMajorVersion") .HasColumnType("integer"); @@ -138,6 +133,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasColumnType("text"); + b.Property("EngineVersion") + .IsRequired() + .HasColumnType("text"); + b.Property("GitHubDeploymentId") .HasColumnType("integer"); @@ -480,11 +479,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => { - b.Property("Id") + b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AccessIdentifier") .IsRequired() @@ -511,6 +510,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("RebootState") .HasColumnType("integer"); + b.Property("TopicPort") + .HasColumnType("integer"); + b.HasKey("Id"); b.HasIndex("CompileJobId"); diff --git a/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs index 30050cf7899..1b1bb5276c0 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/SqlServerDatabaseContextModelSnapshot.cs @@ -13,7 +13,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6") + .HasAnnotation("ProductVersion", "8.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -118,11 +118,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - b.Property("ByondVersion") - .IsRequired() - .HasColumnType("nvarchar(max)") - .HasColumnName("EngineVersion"); - b.Property("DMApiMajorVersion") .HasColumnType("int"); @@ -140,6 +135,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasColumnType("nvarchar(max)"); + b.Property("EngineVersion") + .IsRequired() + .HasColumnType("nvarchar(max)"); + b.Property("GitHubDeploymentId") .HasColumnType("int"); @@ -485,11 +484,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => { - b.Property("Id") + b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("bigint"); - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("AccessIdentifier") .IsRequired() @@ -516,6 +515,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("RebootState") .HasColumnType("int"); + b.Property("TopicPort") + .HasColumnType("int"); + b.HasKey("Id"); b.HasIndex("CompileJobId"); diff --git a/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs b/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs index 3f4daecc39b..29d7469c653 100644 --- a/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs +++ b/src/Tgstation.Server.Host/Database/Migrations/SqliteDatabaseContextModelSnapshot.cs @@ -12,7 +12,7 @@ partial class SqliteDatabaseContextModelSnapshot : ModelSnapshot protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6"); + modelBuilder.HasAnnotation("ProductVersion", "8.0.0"); modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b => { @@ -108,11 +108,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("ByondVersion") - .IsRequired() - .HasColumnType("TEXT") - .HasColumnName("EngineVersion"); - b.Property("DMApiMajorVersion") .HasColumnType("INTEGER"); @@ -130,6 +125,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasColumnType("TEXT"); + b.Property("EngineVersion") + .IsRequired() + .HasColumnType("TEXT"); + b.Property("GitHubDeploymentId") .HasColumnType("INTEGER"); @@ -466,7 +465,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Tgstation.Server.Host.Models.ReattachInformation", b => { - b.Property("Id") + b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); @@ -495,6 +494,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("RebootState") .HasColumnType("INTEGER"); + b.Property("TopicPort") + .HasColumnType("INTEGER"); + b.HasKey("Id"); b.HasIndex("CompileJobId"); diff --git a/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs b/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs index b233f0c0179..3d3d4411cb0 100644 --- a/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs +++ b/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs @@ -22,10 +22,15 @@ public abstract class ReattachInformationBase : DMApiParameters public int ProcessId { get; set; } /// - /// The port DreamDaemon was last listening on. + /// The port the game server was last listening on. /// public ushort Port { get; set; } + /// + /// The port the game server was last listening on for topics. + /// + public ushort? TopicPort { get; set; } + /// /// The current DreamDaemon reboot state. /// @@ -58,6 +63,7 @@ protected ReattachInformationBase(ReattachInformationBase copy) Id = copy.Id; AccessIdentifier = copy.AccessIdentifier; Port = copy.Port; + TopicPort = copy.TopicPort; ProcessId = copy.ProcessId; RebootState = copy.RebootState; LaunchSecurityLevel = copy.LaunchSecurityLevel; From 9711a787a8bf1ea8ebf408bfb3173212ed87063d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 19 Dec 2023 23:23:15 -0500 Subject: [PATCH 544/717] Rename `IProcessBase` functions to avoid language conflicts --- .../Components/Session/SessionController.cs | 6 +++--- .../Components/Watchdog/AdvancedWatchdog.cs | 4 ++-- src/Tgstation.Server.Host/System/IProcessBase.cs | 4 ++-- src/Tgstation.Server.Host/System/Process.cs | 4 ++-- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 56ef1416c2e..51f7cdc126b 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -432,10 +432,10 @@ public void ResetRebootState() public void AdjustPriority(bool higher) => process.AdjustPriority(higher); /// - public void Suspend() => process.Suspend(); + public void SuspendProcess() => process.SuspendProcess(); /// - public void Resume() => process.Resume(); + public void ResumeProcess() => process.ResumeProcess(); /// public IAsyncDisposable ReplaceDmbProvider(IDmbProvider dmbProvider) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs index cf1f30153ba..0b08ed062b1 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs @@ -387,7 +387,7 @@ async ValueTask PerformDmbSwap(SwappableDmbProvider newProvider, CancellationTok var server = Server; try { - server.Suspend(); + server.SuspendProcess(); suspended = true; } catch (Exception ex) @@ -404,7 +404,7 @@ async ValueTask PerformDmbSwap(SwappableDmbProvider newProvider, CancellationTok { // Let this throw hard if it fails if (suspended) - server.Resume(); + server.ResumeProcess(); } } diff --git a/src/Tgstation.Server.Host/System/IProcessBase.cs b/src/Tgstation.Server.Host/System/IProcessBase.cs index 8fc0bd4484e..3d1030f645e 100644 --- a/src/Tgstation.Server.Host/System/IProcessBase.cs +++ b/src/Tgstation.Server.Host/System/IProcessBase.cs @@ -22,12 +22,12 @@ interface IProcessBase /// /// Suspends the process. /// - void Suspend(); + void SuspendProcess(); /// /// Resumes the process. /// - void Resume(); + void ResumeProcess(); /// /// Create a dump file of the process. diff --git a/src/Tgstation.Server.Host/System/Process.cs b/src/Tgstation.Server.Host/System/Process.cs index e6c4c312e91..43620832474 100644 --- a/src/Tgstation.Server.Host/System/Process.cs +++ b/src/Tgstation.Server.Host/System/Process.cs @@ -183,7 +183,7 @@ public void AdjustPriority(bool higher) } /// - public void Suspend() + public void SuspendProcess() { CheckDisposed(); try @@ -199,7 +199,7 @@ public void Suspend() } /// - public void Resume() + public void ResumeProcess() { CheckDisposed(); try diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 0df8a9755c6..c1778e63fa8 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -791,7 +791,7 @@ async Task RunHealthCheckTest(bool checkDump, CancellationToken cancellationToke ValidateSessionId(ddStatus, true); global::System.Console.WriteLine($"WATCHDOG TEST {instanceClient.Metadata.Id}: COMMENCE PROCESS SUSPEND FOR HEALTH CHECK DEATH PID {ourProcessHandler.Id}."); - ourProcessHandler.Suspend(); + ourProcessHandler.SuspendProcess(); global::System.Console.WriteLine($"WATCHDOG TEST {instanceClient.Metadata.Id}: FINISH PROCESS SUSPEND FOR HEALTH CHECK DEATH. WAITING FOR LIFETIME {ourProcessHandler.Id}."); await Task.WhenAny(ourProcessHandler.Lifetime, Task.Delay(TimeSpan.FromMinutes(4), cancellationToken)); From 0883874186fa123d7f405d51a85dc2b30f90dbcf Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 19 Dec 2023 23:24:04 -0500 Subject: [PATCH 545/717] Support graceful OpenDream shutdowns - SessionController now uses `IEngineExectuableLock` to stop servers. - Kills servers by default. Uses the RobustToolbox WatchdogApi for OpenDream. --- .../Components/Engine/EngineExecutableLock.cs | 15 +++- .../Engine/EngineInstallationBase.cs | 18 ++++- .../Components/Engine/IEngineInstallation.cs | 17 +++- .../Engine/OpenDreamInstallation.cs | 79 ++++++++++++++++++- .../Components/Engine/OpenDreamInstaller.cs | 24 +++++- .../Engine/WindowsOpenDreamInstaller.cs | 8 ++ .../Components/Session/SessionController.cs | 23 +++--- src/Tgstation.Server.Host/System/IProcess.cs | 2 +- .../System/IProcessBase.cs | 2 +- .../Engine/TestOpenDreamInstaller.cs | 4 + .../Live/Instance/InstanceTest.cs | 4 + .../Live/Instance/WatchdogTest.cs | 2 +- 12 files changed, 180 insertions(+), 18 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs index 02d9bfe4931..36944a876fb 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs @@ -1,9 +1,13 @@ using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; + using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; #nullable disable @@ -11,7 +15,7 @@ namespace Tgstation.Server.Host.Components.Engine { /// - sealed class EngineExecutableLock : ReferenceCounter, IEngineExecutableLock + class EngineExecutableLock : ReferenceCounter, IEngineExecutableLock { /// public EngineVersion Version => Instance.Version; @@ -51,5 +55,14 @@ public string FormatServerArguments( /// public string FormatCompilerArguments(string dmePath) => Instance.FormatCompilerArguments(dmePath); + + /// + public ValueTask StopServerProcess(ILogger logger, IProcess process, string accessIdentifier, ushort port, CancellationToken cancellationToken) + => Instance.StopServerProcess( + logger, + process, + accessIdentifier, + port, + cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs index 2133bdade40..f2da09f3459 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs @@ -1,12 +1,16 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using System.Web; +using Microsoft.Extensions.Logging; + using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.System; #nullable disable @@ -58,6 +62,18 @@ protected static string EncodeParameters( public abstract string FormatCompilerArguments(string dmePath); /// - public abstract string FormatServerArguments(IDmbProvider dmbProvider, IReadOnlyDictionary parameters, DreamDaemonLaunchParameters launchParameters, string logFilePath); + public abstract string FormatServerArguments( + IDmbProvider dmbProvider, + IReadOnlyDictionary parameters, + DreamDaemonLaunchParameters launchParameters, + string logFilePath); + + /// + public virtual async ValueTask StopServerProcess(ILogger logger, IProcess process, string accessIdentifier, ushort port, CancellationToken cancellationToken) + { + logger.LogTrace("Terminating engine server process..."); + process.Terminate(); + await process.Lifetime; + } } } diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs index 861d6ebe90a..bd7fa9e1804 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs @@ -1,9 +1,13 @@ using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; + using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.System; #nullable disable @@ -53,7 +57,7 @@ public interface IEngineInstallation /// Return the command line arguments for launching with given . /// /// The . - /// The map of parameter s as a . Should NOT include the of . + /// The map of parameter s as a . MUST include . Should NOT include the of . /// The . /// The full path to the log file, if any. /// The formatted arguments . @@ -69,5 +73,16 @@ string FormatServerArguments( /// The full path to the .dme to compile. /// The formatted arguments . string FormatCompilerArguments(string dmePath); + + /// + /// Kills a given engine server . + /// + /// The to write to. + /// The to be terminated. + /// The of the session. + /// The port the server is running on. + /// The for the operation. + /// A representing the running operation. + ValueTask StopServerProcess(ILogger logger, IProcess process, string accessIdentifier, ushort port, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index db3e7a7392d..7e1fc27e47c 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -1,11 +1,22 @@ using System; using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Mime; +using System.Text; +using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; + using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Components.Deployment; +using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.System; +using Tgstation.Server.Host.Utils; #nullable disable @@ -42,22 +53,38 @@ sealed class OpenDreamInstallation : EngineInstallationBase /// readonly IIOManager ioManager; + /// + /// The for the . + /// + readonly IAsyncDelayer asyncDelayer; + + /// + /// The for the . + /// + readonly IAbstractHttpClientFactory httpClientFactory; + /// /// Initializes a new instance of the class. /// /// The value of . + /// The value of . + /// The value of . /// The value of . /// The value of . /// The value of . /// The value of . public OpenDreamInstallation( IIOManager ioManager, + IAsyncDelayer asyncDelayer, + IAbstractHttpClientFactory httpClientFactory, string serverExePath, string compilerExePath, Task installationTask, EngineVersion version) { this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); + this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); ServerExePath = serverExePath ?? throw new ArgumentNullException(nameof(serverExePath)); CompilerExePath = compilerExePath ?? throw new ArgumentNullException(nameof(compilerExePath)); InstallationTask = installationTask ?? throw new ArgumentNullException(nameof(installationTask)); @@ -78,15 +105,65 @@ public override string FormatServerArguments( ArgumentNullException.ThrowIfNull(parameters); ArgumentNullException.ThrowIfNull(launchParameters); + if (!parameters.TryGetValue(DMApiConstants.ParamAccessIdentifier, out var accessIdentifier)) + throw new ArgumentException($"parameters must have \"{DMApiConstants.ParamAccessIdentifier}\" set!", nameof(parameters)); + var parametersString = EncodeParameters(parameters, launchParameters); var loggingEnabled = logFilePath != null; - var arguments = $"--cvar {(loggingEnabled ? $"log.path=\"{ioManager.GetDirectoryName(logFilePath)}\" --cvar log.format=\"{ioManager.GetFileName(logFilePath)}\"" : "log.enabled=false")} --cvar log.runtimelog=false --cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" --cvar opendream.json_path=\"./{dmbProvider.DmbName}\""; + var arguments = $"--cvar {(loggingEnabled ? $"log.path=\"{ioManager.GetDirectoryName(logFilePath)}\" --cvar log.format=\"{ioManager.GetFileName(logFilePath)}\"" : "log.enabled=false")} --cvar watchdog.token={accessIdentifier} --cvar log.runtimelog=false --cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" --cvar opendream.json_path=\"./{dmbProvider.DmbName}\""; return arguments; } /// public override string FormatCompilerArguments(string dmePath) => $"--suppress-unimplemented --notices-enabled \"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\""; + + /// + public override async ValueTask StopServerProcess( + ILogger logger, + IProcess process, + string accessIdentifier, + ushort port, + CancellationToken cancellationToken) + { + const int MaximumTerminationSeconds = 5; + + logger.LogTrace("Attempting Robust.Server graceful exit (Timeout: {seconds}s)...", MaximumTerminationSeconds); + var timeout = asyncDelayer.Delay(TimeSpan.FromSeconds(MaximumTerminationSeconds), cancellationToken); + var lifetime = process.Lifetime; + + using var httpClient = httpClientFactory.CreateClient(); + using var request = new HttpRequestMessage(); + request.Headers.Add("WatchdogToken", accessIdentifier); + request.RequestUri = new Uri($"http://localhost:{port}/shutdown"); + request.Content = new StringContent( + "{\"Reason\":\"TGS session termination\"}", + Encoding.UTF8, + new MediaTypeHeaderValue(MediaTypeNames.Application.Json)); + request.Method = HttpMethod.Post; + + var responseTask = httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken); + + await Task.WhenAny(timeout, lifetime, responseTask); + if (responseTask.IsCompleted) + { + using var response = await responseTask; + if (response.IsSuccessStatusCode) + { + logger.LogDebug("Robust.Server responded to the shutdown command successfully. Waiting for exit..."); + await Task.WhenAny(timeout, lifetime); + } + } + + if (lifetime.IsCompleted) + { + logger.LogTrace("Robust.Server gracefully exited"); + return; + } + + logger.LogWarning("Robust.Server graceful exit timed out!"); + await base.StopServerProcess(logger, process, accessIdentifier, port, cancellationToken); + } } } diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index cefdadd5047..886b419a3e5 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -8,12 +8,14 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Common.Extensions; +using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Common; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.System; +using Tgstation.Server.Host.Utils; #nullable disable @@ -52,6 +54,11 @@ class OpenDreamInstaller : EngineInstallerBase /// protected IProcessExecutor ProcessExecutor { get; } + /// + /// The for the . + /// + protected GeneralConfiguration GeneralConfiguration { get; } + /// /// The for the . /// @@ -63,9 +70,14 @@ class OpenDreamInstaller : EngineInstallerBase readonly IRepositoryManager repositoryManager; /// - /// The for the . + /// The for the . /// - protected GeneralConfiguration GeneralConfiguration { get; } + readonly IAsyncDelayer asyncDelayer; + + /// + /// The for the . + /// + readonly IAbstractHttpClientFactory httpClientFactory; /// /// Initializes a new instance of the class. @@ -75,6 +87,8 @@ class OpenDreamInstaller : EngineInstallerBase /// The value of . /// The value of . /// The value of . + /// The value of . + /// The value of . /// The containing value of . public OpenDreamInstaller( IIOManager ioManager, @@ -82,12 +96,16 @@ public OpenDreamInstaller( IPlatformIdentifier platformIdentifier, IProcessExecutor processExecutor, IRepositoryManager repositoryManager, + IAsyncDelayer asyncDelayer, + IAbstractHttpClientFactory httpClientFactory, IOptions generalConfigurationOptions) : base(ioManager, logger) { this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); ProcessExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); this.repositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager)); + this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); + this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); GeneralConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } @@ -101,6 +119,8 @@ public override IEngineInstallation CreateInstallation(EngineVersion version, st GetExecutablePaths(path, out var serverExePath, out var compilerExePath); return new OpenDreamInstallation( IOManager, + asyncDelayer, + httpClientFactory, serverExePath, compilerExePath, installationTask, diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index 3aa19f3e384..2fb12e80def 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -7,11 +7,13 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Common.Extensions; +using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.System; +using Tgstation.Server.Host.Utils; #nullable disable @@ -35,6 +37,8 @@ sealed class WindowsOpenDreamInstaller : OpenDreamInstaller /// The for the . /// The for the . /// The for the . + /// The for the . + /// The for the . /// The of for the . /// The value of . public WindowsOpenDreamInstaller( @@ -43,6 +47,8 @@ public WindowsOpenDreamInstaller( IPlatformIdentifier platformIdentifier, IProcessExecutor processExecutor, IRepositoryManager repositoryManager, + IAsyncDelayer asyncDelayer, + IAbstractHttpClientFactory httpClientFactory, IOptions generalConfigurationOptions, IFilesystemLinkFactory linkFactory) : base( @@ -51,6 +57,8 @@ public WindowsOpenDreamInstaller( platformIdentifier, processExecutor, repositoryManager, + asyncDelayer, + httpClientFactory, generalConfigurationOptions) { this.linkFactory = linkFactory ?? throw new ArgumentNullException(nameof(linkFactory)); diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 51f7cdc126b..9fbd96cca9a 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -133,7 +133,7 @@ async Task Wrap() /// /// The for the . /// - readonly IEngineExecutableLock byondLock; + readonly IEngineExecutableLock engineLock; /// /// The for the . @@ -226,7 +226,7 @@ async Task Wrap() /// The value of . /// The owning . /// The value of . - /// The value of . + /// The value of . /// The value of . /// The used to populate . /// The value of . @@ -242,7 +242,7 @@ public SessionController( ReattachInformation reattachInformation, Api.Models.Instance metadata, IProcess process, - IEngineExecutableLock byondLock, + IEngineExecutableLock engineLock, Byond.TopicSender.ITopicClient byondTopicSender, IChatTrackingContext chatTrackingContext, IBridgeRegistrar bridgeRegistrar, @@ -259,7 +259,7 @@ public SessionController( ReattachInformation = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation)); this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); this.process = process ?? throw new ArgumentNullException(nameof(process)); - this.byondLock = byondLock ?? throw new ArgumentNullException(nameof(byondLock)); + this.engineLock = engineLock ?? throw new ArgumentNullException(nameof(engineLock)); this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender)); this.chatTrackingContext = chatTrackingContext ?? throw new ArgumentNullException(nameof(chatTrackingContext)); ArgumentNullException.ThrowIfNull(bridgeRegistrar); @@ -340,16 +340,21 @@ public async ValueTask DisposeAsync() Logger.LogTrace("Disposing..."); reattachTopicCts.Cancel(); - var semaphoreLockTask = TopicSendSemaphore.Lock(CancellationToken.None); // DCT: None available + var cancellationToken = CancellationToken.None; // DCT: None available + var semaphoreLockTask = TopicSendSemaphore.Lock(cancellationToken); if (!released) { - process.Terminate(); - await process.Lifetime; + await engineLock.StopServerProcess( + Logger, + process, + ReattachInformation.AccessIdentifier, + ReattachInformation.Port, + cancellationToken); } await process.DisposeAsync(); - byondLock.Dispose(); + engineLock.Dispose(); bridgeRegistration?.Dispose(); var regularDmbDisposeTask = ReattachInformation.Dmb.DisposeAsync(); var initialDmb = ReattachInformation.InitialDmb; @@ -395,7 +400,7 @@ public ValueTask Release() ReattachInformation.Dmb.KeepAlive(); ReattachInformation.InitialDmb?.KeepAlive(); - byondLock.DoNotDeleteThisSession(); + engineLock.DoNotDeleteThisSession(); released = true; return DisposeAsync(); } diff --git a/src/Tgstation.Server.Host/System/IProcess.cs b/src/Tgstation.Server.Host/System/IProcess.cs index af7409ee9d8..b0783cbd7e0 100644 --- a/src/Tgstation.Server.Host/System/IProcess.cs +++ b/src/Tgstation.Server.Host/System/IProcess.cs @@ -7,7 +7,7 @@ namespace Tgstation.Server.Host.System /// /// Abstraction over a . /// - interface IProcess : IProcessBase, IAsyncDisposable + public interface IProcess : IProcessBase, IAsyncDisposable { /// /// The ' ID. diff --git a/src/Tgstation.Server.Host/System/IProcessBase.cs b/src/Tgstation.Server.Host/System/IProcessBase.cs index 3d1030f645e..d7a20f43b7e 100644 --- a/src/Tgstation.Server.Host/System/IProcessBase.cs +++ b/src/Tgstation.Server.Host/System/IProcessBase.cs @@ -6,7 +6,7 @@ namespace Tgstation.Server.Host.System /// /// Represents process lifetime. /// - interface IProcessBase + public interface IProcessBase { /// /// The resulting in the exit code of the process or if the process was detached. diff --git a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs index 6b8024ddac8..30d995f99c1 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs @@ -9,10 +9,12 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.System; +using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.Components.Engine.Tests { @@ -69,6 +71,8 @@ static async Task RepoDownloadTest(bool needsClone) Mock.Of(), Mock.Of(), mockRepositoryManager.Object, + Mock.Of(), + Mock.Of(), mockGeneralConfigOptions.Object); var data = await installer.DownloadVersion( diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index a50d4a65043..76bfa30b234 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -17,6 +17,7 @@ using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client; using Tgstation.Server.Client.Components; +using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Events; @@ -25,6 +26,7 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.System; +using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Tests.Live.Instance { @@ -116,6 +118,8 @@ public static async ValueTask DownloadEngineVersion( Mock.Of>(), Mock.Of>(), genConfig), + Mock.Of(), + Mock.Of(), mockOptions.Object) : new PlatformIdentifier().IsWindows ? new WindowsByondInstaller( diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index c1778e63fa8..4b08e3ae1fb 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -1013,7 +1013,7 @@ ushort FindTopicPort() Assert.IsNotNull(sessionObj); var session = (ISessionController)sessionObj; - return session.ReattachInformation.Port; + return session.ReattachInformation.TopicPort ?? session.ReattachInformation.Port; } // - Uses instance manager concrete From 523b3aa86e7e8155e32ced54c245536f6243be85 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:02:52 -0500 Subject: [PATCH 546/717] Update `Z.EntityFramework.Plus.EFCore` --- src/Tgstation.Server.Host/Tgstation.Server.Host.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index 6bb958fb744..733400da3de 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -126,7 +126,7 @@ - + From 62d5dcb7ccf98d9e37f48e8e7da33b86a8f62a08 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:09:56 -0500 Subject: [PATCH 547/717] Nullify `DreamDaemonController` --- .../Controllers/DreamDaemonController.cs | 41 +++++++++---------- .../Controllers/InstanceRequiredController.cs | 5 +++ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index 7c874e536a3..f83ec8410f5 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -25,8 +25,6 @@ #pragma warning disable API1001 // Action method returns a success result without a corresponding ProducesResponseType. Somehow this happens ONLY IN THIS CONTROLLER??? -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -174,7 +172,7 @@ public async ValueTask Update([FromBody] DreamDaemonRequest model if (current == default) return this.Gone(); - if (model.Port.HasValue && model.Port.Value != current.Port.Value) + if (model.Port.HasValue && model.Port.Value != current.Port!.Value) { var verifiedPort = await portAllocator .GetAvailablePort( @@ -203,14 +201,15 @@ bool CheckModified(Expression x.AllowWebClient, DreamDaemonRights.SetWebClient) || CheckModified(x => x.AutoStart, DreamDaemonRights.SetAutoStart) || CheckModified(x => x.Port, DreamDaemonRights.SetPort) || CheckModified(x => x.SecurityLevel, DreamDaemonRights.SetSecurity) || CheckModified(x => x.Visibility, DreamDaemonRights.SetVisibility) - || (model.SoftRestart.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftRestart)) - || (model.SoftShutdown.HasValue && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.SoftShutdown)) - || (!String.IsNullOrWhiteSpace(model.BroadcastMessage) && !AuthenticationContext.InstancePermissionSet.DreamDaemonRights.Value.HasFlag(DreamDaemonRights.BroadcastMessage)) + || (model.SoftRestart.HasValue && !ddRights.HasFlag(DreamDaemonRights.SoftRestart)) + || (model.SoftShutdown.HasValue && !ddRights.HasFlag(DreamDaemonRights.SoftShutdown)) + || (!String.IsNullOrWhiteSpace(model.BroadcastMessage) && !ddRights.HasFlag(DreamDaemonRights.BroadcastMessage)) || CheckModified(x => x.StartupTimeout, DreamDaemonRights.SetStartupTimeout) || CheckModified(x => x.HealthCheckSeconds, DreamDaemonRights.SetHealthCheckInterval) || CheckModified(x => x.DumpOnHealthCheckRestart, DreamDaemonRights.CreateDump) @@ -310,7 +309,7 @@ await jobManager.RegisterOperation( /// If there was a settings change made that forced a switch to . /// The for the operation. /// A resulting in the of the operation. - ValueTask ReadImpl(DreamDaemonSettings settings, bool knownForcedReboot, CancellationToken cancellationToken) + ValueTask ReadImpl(DreamDaemonSettings? settings, bool knownForcedReboot, CancellationToken cancellationToken) => WithComponentInstance(async instance => { var dd = instance.Watchdog; @@ -324,7 +323,7 @@ ValueTask ReadImpl(DreamDaemonSettings settings, bool knownForced .Instances .AsQueryable() .Where(x => x.Id == Instance.Id) - .Select(x => x.DreamDaemonSettings) + .Select(x => x.DreamDaemonSettings!) .FirstOrDefaultAsync(cancellationToken); if (settings == default) return this.Gone(); @@ -336,13 +335,13 @@ ValueTask ReadImpl(DreamDaemonSettings settings, bool knownForced var alphaActive = dd.AlphaIsActive; var llp = dd.LastLaunchParameters; var rstate = dd.RebootState; - result.AutoStart = settings.AutoStart.Value; - result.CurrentPort = llp?.Port.Value; - result.CurrentSecurity = llp?.SecurityLevel.Value; - result.CurrentVisibility = llp?.Visibility.Value; - result.CurrentAllowWebclient = llp?.AllowWebClient.Value; - result.Port = settings.Port.Value; - result.AllowWebClient = settings.AllowWebClient.Value; + result.AutoStart = settings.AutoStart!.Value; + result.CurrentPort = llp?.Port!.Value; + result.CurrentSecurity = llp?.SecurityLevel!.Value; + result.CurrentVisibility = llp?.Visibility!.Value; + result.CurrentAllowWebclient = llp?.AllowWebClient!.Value; + result.Port = settings.Port!.Value; + result.AllowWebClient = settings.AllowWebClient!.Value; var firstIteration = true; do @@ -359,18 +358,18 @@ ValueTask ReadImpl(DreamDaemonSettings settings, bool knownForced } while (result.Status == WatchdogStatus.Online && !result.SessionId.HasValue); // this is the one invalid combo, it's not that racy - result.SecurityLevel = settings.SecurityLevel.Value; - result.Visibility = settings.Visibility.Value; + result.SecurityLevel = settings.SecurityLevel!.Value; + result.Visibility = settings.Visibility!.Value; result.SoftRestart = rstate == RebootState.Restart; result.SoftShutdown = rstate == RebootState.Shutdown; if (rstate == RebootState.Normal && knownForcedReboot) result.SoftRestart = true; - result.StartupTimeout = settings.StartupTimeout.Value; - result.HealthCheckSeconds = settings.HealthCheckSeconds.Value; - result.DumpOnHealthCheckRestart = settings.DumpOnHealthCheckRestart.Value; - result.TopicRequestTimeout = settings.TopicRequestTimeout.Value; + result.StartupTimeout = settings.StartupTimeout!.Value; + result.HealthCheckSeconds = settings.HealthCheckSeconds!.Value; + result.DumpOnHealthCheckRestart = settings.DumpOnHealthCheckRestart!.Value; + result.TopicRequestTimeout = settings.TopicRequestTimeout!.Value; result.AdditionalParameters = settings.AdditionalParameters; result.StartProfiler = settings.StartProfiler; result.LogOutput = settings.LogOutput; diff --git a/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs b/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs index 68dec105043..1e36f544b43 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs @@ -19,6 +19,11 @@ public abstract class InstanceRequiredController : ComponentInterfacingControlle /// protected new Models.Instance Instance => base.Instance!; + /// + /// The for the request. + /// + protected Models.InstancePermissionSet InstancePermissionSet => AuthenticationContext.InstancePermissionSet!; + /// /// Initializes a new instance of the class. /// From ecf95607e821c9934b0f832cbe0609c0babc5c46 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:15:45 -0500 Subject: [PATCH 548/717] Nullify `DreamMakerController` --- .../Controllers/ApiController.cs | 4 +- .../Controllers/DreamMakerController.cs | 37 ++++++++++--------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/ApiController.cs b/src/Tgstation.Server.Host/Controllers/ApiController.cs index ea8c4c32093..bad2e6c10f1 100644 --- a/src/Tgstation.Server.Host/Controllers/ApiController.cs +++ b/src/Tgstation.Server.Host/Controllers/ApiController.cs @@ -267,7 +267,7 @@ protected IActionResult HeadersIssue(HeadersException headersException) /// /// The of model being generated and returned. /// A resulting in a resulting in the generated . - /// A to transform the s after being queried. + /// Optional to transform the s after being queried. /// The requested page from the query. /// The requested page size from the query. /// The for the operation. @@ -297,7 +297,7 @@ protected ValueTask Paginated( /// A resulting in the for the operation. protected ValueTask Paginated( Func>> queryGenerator, - Func resultTransformer, + Func? resultTransformer, int? pageQuery, int? pageSizeQuery, CancellationToken cancellationToken) diff --git a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs index 9401f646d9f..d1ef45fe484 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs @@ -21,8 +21,6 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -87,6 +85,10 @@ public async ValueTask Read(CancellationToken cancellationToken) .AsQueryable() .Where(x => x.InstanceId == Instance.Id) .FirstOrDefaultAsync(cancellationToken); + + if (dreamMakerSettings == null) + return this.Gone(); + return Json(dreamMakerSettings.ToApi()); } @@ -189,9 +191,10 @@ public async ValueTask Update([FromBody] DreamMakerRequest model, if (hostModel == null) return this.Gone(); + var dreamMakerRights = InstancePermissionSet.DreamMakerRights!.Value; if (model.ProjectName != null) { - if (!AuthenticationContext.InstancePermissionSet.DreamMakerRights.Value.HasFlag(DreamMakerRights.SetDme)) + if (!dreamMakerRights.HasFlag(DreamMakerRights.SetDme)) return Forbid(); if (model.ProjectName.Length == 0) hostModel.ProjectName = null; @@ -201,10 +204,10 @@ public async ValueTask Update([FromBody] DreamMakerRequest model, if (model.ApiValidationPort.HasValue) { - if (!AuthenticationContext.InstancePermissionSet.DreamMakerRights.Value.HasFlag(DreamMakerRights.SetApiValidationPort)) + if (!dreamMakerRights.HasFlag(DreamMakerRights.SetApiValidationPort)) return Forbid(); - if (model.ApiValidationPort.Value != hostModel.ApiValidationPort.Value) + if (model.ApiValidationPort.Value != hostModel.ApiValidationPort!.Value) { var verifiedPort = await portAllocator .GetAvailablePort( @@ -220,28 +223,28 @@ public async ValueTask Update([FromBody] DreamMakerRequest model, if (model.ApiValidationSecurityLevel.HasValue) { - if (!AuthenticationContext.InstancePermissionSet.DreamMakerRights.Value.HasFlag(DreamMakerRights.SetSecurityLevel)) + if (!dreamMakerRights.HasFlag(DreamMakerRights.SetSecurityLevel)) return Forbid(); hostModel.ApiValidationSecurityLevel = model.ApiValidationSecurityLevel; } if (model.RequireDMApiValidation.HasValue) { - if (!AuthenticationContext.InstancePermissionSet.DreamMakerRights.Value.HasFlag(DreamMakerRights.SetApiValidationRequirement)) + if (!dreamMakerRights.HasFlag(DreamMakerRights.SetApiValidationRequirement)) return Forbid(); hostModel.RequireDMApiValidation = model.RequireDMApiValidation; } if (model.Timeout.HasValue) { - if (!AuthenticationContext.InstancePermissionSet.DreamMakerRights.Value.HasFlag(DreamMakerRights.SetTimeout)) + if (!dreamMakerRights.HasFlag(DreamMakerRights.SetTimeout)) return Forbid(); hostModel.Timeout = model.Timeout; } await DatabaseContext.Save(cancellationToken); - if ((AuthenticationContext.GetRight(RightsType.DreamMaker) & (ulong)DreamMakerRights.Read) == 0) + if (!dreamMakerRights.HasFlag(DreamMakerRights.Read)) return NoContent(); return await Read(cancellationToken); @@ -254,17 +257,17 @@ public async ValueTask Update([FromBody] DreamMakerRequest model, IQueryable BaseCompileJobsQuery() => DatabaseContext .CompileJobs .AsQueryable() - .Include(x => x.Job) + .Include(x => x.Job!) .ThenInclude(x => x.StartedBy) - .Include(x => x.Job) + .Include(x => x.Job!) .ThenInclude(x => x.Instance) - .Include(x => x.RevisionInformation) - .ThenInclude(x => x.PrimaryTestMerge) + .Include(x => x.RevisionInformation!) + .ThenInclude(x => x.PrimaryTestMerge!) .ThenInclude(x => x.MergedBy) .Include(x => x.RevisionInformation) - .ThenInclude(x => x.ActiveTestMerges) - .ThenInclude(x => x.TestMerge) - .ThenInclude(x => x.MergedBy) - .Where(x => x.Job.Instance.Id == Instance.Id); + .ThenInclude(x => x.ActiveTestMerges!) + .ThenInclude(x => x!.TestMerge) + .ThenInclude(x => x!.MergedBy) + .Where(x => x.Job.Instance!.Id == Instance.Id); } } From 261d56655b5b328d276fb60796b516a797093fd0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:16:38 -0500 Subject: [PATCH 549/717] Remove unnecessary warning suppression --- src/Tgstation.Server.Host/Controllers/DreamMakerController.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs index d1ef45fe484..680f8da7319 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs @@ -27,7 +27,6 @@ namespace Tgstation.Server.Host.Controllers /// for managing the deployment system. /// [Route(Routes.DreamMaker)] -#pragma warning disable CA1506 // TODO: Decomplexify public sealed class DreamMakerController : InstanceRequiredController { /// From c9bb84236c7f79154bcf167c162e3446fd9d38c0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:23:41 -0500 Subject: [PATCH 550/717] Nullify `EngineController` --- .../Controllers/EngineController.cs | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/EngineController.cs b/src/Tgstation.Server.Host/Controllers/EngineController.cs index a65ac974557..2f83a1afd86 100644 --- a/src/Tgstation.Server.Host/Controllers/EngineController.cs +++ b/src/Tgstation.Server.Host/Controllers/EngineController.cs @@ -23,8 +23,6 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -122,7 +120,7 @@ public ValueTask List([FromQuery] int? page, [FromQuery] int? pag EngineVersion = x, }) .AsQueryable() - .OrderBy(x => x.EngineVersion.ToString()))), + .OrderBy(x => x.EngineVersion!.ToString()))), null, page, pageSize, @@ -157,16 +155,16 @@ public async ValueTask Update([FromBody] EngineVersionRequest mod var uploadingZip = model.UploadCustomZip == true; - var userByondRights = AuthenticationContext.InstancePermissionSet.EngineRights.Value; - var isByondEngine = model.EngineVersion.Engine.Value == EngineType.Byond; + var engineRights = InstancePermissionSet.EngineRights!.Value; + var isByondEngine = model.EngineVersion!.Engine!.Value == EngineType.Byond; var officialPerm = isByondEngine ? EngineRights.InstallOfficialOrChangeActiveByondVersion : EngineRights.InstallOfficialOrChangeActiveOpenDreamVersion; var customPerm = isByondEngine ? EngineRights.InstallCustomByondVersion : EngineRights.InstallCustomOpenDreamVersion; - if ((!userByondRights.HasFlag(officialPerm) && !uploadingZip) - || (!userByondRights.HasFlag(customPerm) && uploadingZip)) + if ((!engineRights.HasFlag(officialPerm) && !uploadingZip) + || (!engineRights.HasFlag(customPerm) && uploadingZip)) return Forbid(); // remove cruff fields @@ -219,7 +217,7 @@ public async ValueTask Update([FromBody] EngineVersionRequest mod EngineRights.CancelInstall); job.Description += $" {model.EngineVersion}"; - IFileUploadTicket fileUploadTicket = null; + IFileUploadTicket? fileUploadTicket = null; if (uploadingZip) fileUploadTicket = fileTransferService.CreateUpload(FileUploadStreamKind.None); @@ -229,7 +227,7 @@ await jobManager.RegisterOperation( job, async (core, databaseContextFactory, paramJob, progressHandler, jobCancellationToken) => { - MemoryStream zipFileStream = null; + MemoryStream? zipFileStream = null; if (fileUploadTicket != null) await using (fileUploadTicket) { @@ -293,18 +291,19 @@ public async ValueTask Delete([FromBody] EngineVersionDeleteReque if (earlyOut != null) return earlyOut; - var notInstalledResponse = await WithComponentInstance( + var engineVersion = model.EngineVersion!; + var notInstalledResponse = await WithComponentInstanceNullable( instance => { var byondManager = instance.EngineManager; - if (model.EngineVersion.Equals(byondManager.ActiveVersion)) - return ValueTask.FromResult( + if (engineVersion.Equals(byondManager.ActiveVersion)) + return ValueTask.FromResult( Conflict(new ErrorMessageResponse(ErrorCode.EngineCannotDeleteActiveVersion))); - var versionNotInstalled = !byondManager.InstalledVersions.Any(x => x.Equals(model.EngineVersion)); + var versionNotInstalled = !byondManager.InstalledVersions.Any(x => x.Equals(engineVersion)); - return ValueTask.FromResult( + return ValueTask.FromResult( versionNotInstalled ? this.Gone() : null); @@ -313,24 +312,24 @@ public async ValueTask Delete([FromBody] EngineVersionDeleteReque if (notInstalledResponse != null) return notInstalledResponse; - var isByondVersion = model.EngineVersion.Engine.Value == EngineType.Byond; + var isByondVersion = engineVersion.Engine!.Value == EngineType.Byond; // run the install through the job manager var cancelRight = isByondVersion - ? model.EngineVersion.CustomIteration.HasValue + ? engineVersion.CustomIteration.HasValue ? EngineRights.InstallCustomByondVersion : EngineRights.InstallOfficialOrChangeActiveByondVersion - : model.EngineVersion.CustomIteration.HasValue + : engineVersion.CustomIteration.HasValue ? EngineRights.InstallOfficialOrChangeActiveOpenDreamVersion : EngineRights.InstallCustomOpenDreamVersion; var job = Models.Job.Create(JobCode.EngineDelete, AuthenticationContext.User, Instance, cancelRight); - job.Description += $" {model.EngineVersion}"; + job.Description += $" {engineVersion}"; await jobManager.RegisterOperation( job, (instanceCore, databaseContextFactory, job, progressReporter, jobCancellationToken) - => instanceCore.EngineManager.DeleteVersion(progressReporter, model.EngineVersion, jobCancellationToken), + => instanceCore.EngineManager.DeleteVersion(progressReporter, engineVersion, jobCancellationToken), cancellationToken); var apiResponse = job.ToApi(); @@ -341,8 +340,8 @@ await jobManager.RegisterOperation( /// Validate and normalize a given . /// /// The to validate and normalize. - /// The to return, if any. - BadRequestObjectResult ValidateEngineVersion(EngineVersion version) + /// The to return, if any. otherwise. + BadRequestObjectResult? ValidateEngineVersion(EngineVersion? version) { if (version == null || !version.Engine.HasValue) return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); @@ -359,7 +358,7 @@ BadRequestObjectResult ValidateEngineVersion(EngineVersion version) if (isByond) { - version.Version = NormalizeByondVersion(version.Version); + version.Version = NormalizeByondVersion(version.Version!); if (version.Version.Build != -1) return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); } From a5f69bf25429778c954d470e60a838e8f29f70e1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:42:46 -0500 Subject: [PATCH 551/717] Nullify `InstanceController` Also switch to using job codes for move job detection. --- src/Tgstation.Server.Api/Models/ErrorCode.cs | 6 +- src/Tgstation.Server.Api/Models/JobCode.cs | 2 +- .../Controllers/InstanceController.cs | 84 +++++++++---------- 3 files changed, 45 insertions(+), 47 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/ErrorCode.cs b/src/Tgstation.Server.Api/Models/ErrorCode.cs index 886816346a7..28f39a76386 100644 --- a/src/Tgstation.Server.Api/Models/ErrorCode.cs +++ b/src/Tgstation.Server.Api/Models/ErrorCode.cs @@ -150,10 +150,10 @@ public enum ErrorCode : uint InstanceLimitReached, /// - /// Attempted to create an with a whitespace . + /// Attempted to create an with a whitespace or . /// - [Description("Instance names cannot be whitespace!")] - InstanceWhitespaceName, + [Description("Instance names and paths cannot be whitespace!")] + InstanceWhitespaceNameOrPath, /// /// The header was required but not set. diff --git a/src/Tgstation.Server.Api/Models/JobCode.cs b/src/Tgstation.Server.Api/Models/JobCode.cs index e82600b3022..be5db8d5a6b 100644 --- a/src/Tgstation.Server.Api/Models/JobCode.cs +++ b/src/Tgstation.Server.Api/Models/JobCode.cs @@ -16,7 +16,7 @@ public enum JobCode : byte /// /// When the instance is being moved. /// - [Description("Instance move")] + [Description("Move instance")] Move, /// diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index 471a0fd0067..ddad25bca77 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Linq.Expressions; @@ -29,8 +30,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -45,11 +44,6 @@ public sealed class InstanceController : ComponentInterfacingController /// public const string InstanceAttachFileName = "TGS4_ALLOW_INSTANCE_ATTACH"; - /// - /// Prefix for move s. - /// - const string MoveInstanceJobPrefix = "Move instance ID "; - /// /// The for the . /// @@ -147,8 +141,8 @@ public async ValueTask Create([FromBody] InstanceCreateRequest mo { ArgumentNullException.ThrowIfNull(model); - if (String.IsNullOrWhiteSpace(model.Name)) - return BadRequest(new ErrorMessageResponse(ErrorCode.InstanceWhitespaceName)); + if (String.IsNullOrWhiteSpace(model.Name) || String.IsNullOrWhiteSpace(model.Path)) + return BadRequest(new ErrorMessageResponse(ErrorCode.InstanceWhitespaceNameOrPath)); var unNormalizedPath = model.Path; var targetInstancePath = NormalizePath(unNormalizedPath); @@ -172,7 +166,7 @@ bool InstanceIsChildOf(string otherPath) return Conflict(new ErrorMessageResponse(ErrorCode.InstanceAtConflictingPath)); // Validate it's not a child of any other instance - IActionResult earlyOut = null; + IActionResult? earlyOut = null; ulong countOfOtherInstances = 0; using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) { @@ -192,7 +186,7 @@ await DatabaseContext { if (++countOfOtherInstances >= generalConfiguration.InstanceLimit) earlyOut ??= Conflict(new ErrorMessageResponse(ErrorCode.InstanceLimitReached)); - else if (InstanceIsChildOf(otherInstance.Path)) + else if (InstanceIsChildOf(otherInstance.Path!)) earlyOut ??= Conflict(new ErrorMessageResponse(ErrorCode.InstanceAtConflictingPath)); if (earlyOut != null && !newCancellationToken.IsCancellationRequested) @@ -308,15 +302,16 @@ public async ValueTask Delete(long id, CancellationToken cancella .FirstOrDefaultAsync(cancellationToken); if (originalModel == default) return this.Gone(); - if (originalModel.Online.Value) + if (originalModel.Online!.Value) return Conflict(new ErrorMessageResponse(ErrorCode.InstanceDetachOnline)); DatabaseContext.Instances.Remove(originalModel); - var attachFileName = ioManager.ConcatPath(originalModel.Path, InstanceAttachFileName); + var originalPath = originalModel.Path!; + var attachFileName = ioManager.ConcatPath(originalPath, InstanceAttachFileName); try { - if (await ioManager.DirectoryExists(originalModel.Path, cancellationToken)) + if (await ioManager.DirectoryExists(originalPath, cancellationToken)) await ioManager.WriteAllBytes(attachFileName, Array.Empty(), cancellationToken); } catch (OperationCanceledException) @@ -355,14 +350,15 @@ public async ValueTask Update([FromBody] InstanceUpdateRequest mo .Where(x => x.Id == model.Id && x.SwarmIdentifer == swarmConfiguration.Identifier); var moveJob = await InstanceQuery() - .SelectMany(x => x.Jobs). - Where(x => !x.StoppedAt.HasValue && x.Description.StartsWith(MoveInstanceJobPrefix)) - .Select(x => new Job(x.Id.Value)).FirstOrDefaultAsync(cancellationToken); + .SelectMany(x => x.Jobs) + .Where(x => !x.StoppedAt.HasValue && x.JobCode == JobCode.Move) + .Select(x => new Job(x.Id!.Value)) + .FirstOrDefaultAsync(cancellationToken); - if (moveJob != default) + if (moveJob != null) { // don't allow them to cancel it if they can't start it. - if (!AuthenticationContext.PermissionSet.InstanceManagerRights.Value.HasFlag(InstanceManagerRights.Relocate)) + if (!AuthenticationContext.PermissionSet.InstanceManagerRights!.Value.HasFlag(InstanceManagerRights.Relocate)) return Forbid(); await jobManager.CancelJob(moveJob, AuthenticationContext.User, true, cancellationToken); // cancel it now } @@ -395,8 +391,9 @@ bool CheckModified(Expression> expression, Insta return false; } - string originalModelPath = null; - string rawPath = null; + string? originalModelPath = null; + string? rawPath = null; + var originalOnline = originalModel.Online!.Value; if (model.Path != null) { rawPath = NormalizePath(model.Path); @@ -405,7 +402,7 @@ bool CheckModified(Expression> expression, Insta { if (!userRights.HasFlag(InstanceManagerRights.Relocate)) return Forbid(); - if (originalModel.Online.Value && model.Online != true) + if (originalOnline && model.Online != true) return Conflict(new ErrorMessageResponse(ErrorCode.InstanceRelocateOnline)); var dirExistsTask = ioManager.DirectoryExists(model.Path, cancellationToken); @@ -417,8 +414,7 @@ bool CheckModified(Expression> expression, Insta } } - var oldAutoUpdateInterval = originalModel.AutoUpdateInterval.Value; - var originalOnline = originalModel.Online.Value; + var oldAutoUpdateInterval = originalModel.AutoUpdateInterval!.Value; var renamed = model.Name != null && originalModel.Name != model.Name; if (CheckModified(x => x.AutoUpdateInterval, InstanceManagerRights.SetAutoUpdate) @@ -445,7 +441,7 @@ bool CheckModified(Expression> expression, Insta if (renamed) { // ignoring retval because we don't care if it's offline - await WithComponentInstance( + await WithComponentInstanceNullable( async componentInstance => { await componentInstance.InstanceRenamed(originalModel.Name, cancellationToken); @@ -454,7 +450,7 @@ await WithComponentInstance( originalModel); } - var oldAutoStart = originalModel.DreamDaemonSettings.AutoStart; + var oldAutoStart = originalModel.DreamDaemonSettings!.AutoStart; try { if (originalOnline && model.Online == false) @@ -489,7 +485,7 @@ await WithComponentInstance( var moving = originalModelPath != null; if (moving) { - var description = $"{MoveInstanceJobPrefix}{originalModel.Id} from {originalModelPath} to {rawPath}"; + var description = $"Move instance ID {originalModel.Id} from {originalModelPath} to {rawPath}"; var job = Job.Create(JobCode.Move, AuthenticationContext.User, originalModel, InstanceManagerRights.Relocate); job.Description = description; @@ -504,7 +500,7 @@ await jobManager.RegisterOperation( if (model.AutoUpdateInterval.HasValue && oldAutoUpdateInterval != model.AutoUpdateInterval) { // ignoring retval because we don't care if it's offline - await WithComponentInstance( + await WithComponentInstanceNullable( async componentInstance => { await componentInstance.SetAutoUpdateInterval(model.AutoUpdateInterval.Value); @@ -540,9 +536,9 @@ public async ValueTask List( .Instances .AsQueryable() .Where(x => x.SwarmIdentifer == swarmConfiguration.Identifier); - if (!AuthenticationContext.PermissionSet.InstanceManagerRights.Value.HasFlag(InstanceManagerRights.List)) + if (!AuthenticationContext.PermissionSet.InstanceManagerRights!.Value.HasFlag(InstanceManagerRights.List)) query = query - .Where(x => x.InstancePermissionSets.Any(y => y.PermissionSetId == AuthenticationContext.PermissionSet.Id.Value)) + .Where(x => x.InstancePermissionSets.Any(y => y.PermissionSetId == AuthenticationContext.PermissionSet.Id)) .Where(x => x.InstancePermissionSets.Any(instanceUser => instanceUser.EngineRights != EngineRights.None || instanceUser.ChatBotRights != ChatBotRights.None || @@ -557,8 +553,9 @@ public async ValueTask List( var moveJobs = await GetBaseQuery() .SelectMany(x => x.Jobs) - .Where(x => !x.StoppedAt.HasValue && x.Description.StartsWith(MoveInstanceJobPrefix)) - .Include(x => x.StartedBy).ThenInclude(x => x.CreatedBy) + .Where(x => !x.StoppedAt.HasValue && x.JobCode == JobCode.Move) + .Include(x => x.StartedBy!) + .ThenInclude(x => x.CreatedBy) .Include(x => x.Instance) .ToListAsync(cancellationToken); @@ -571,7 +568,7 @@ public async ValueTask List( async instance => { needsUpdate |= ValidateInstanceOnlineStatus(instance); - instance.MoveJob = moveJobs.FirstOrDefault(x => x.Instance.Id == instance.Id)?.ToApi(); + instance.MoveJob = moveJobs.FirstOrDefault(x => x.Instance!.Id == instance.Id)?.ToApi(); await CheckAccessible(instance, cancellationToken); }, page, @@ -598,7 +595,7 @@ public async ValueTask List( [ProducesResponseType(typeof(ErrorMessageResponse), 410)] public async ValueTask GetId(long id, CancellationToken cancellationToken) { - var cantList = !AuthenticationContext.PermissionSet.InstanceManagerRights.Value.HasFlag(InstanceManagerRights.List); + var cantList = !AuthenticationContext.PermissionSet.InstanceManagerRights!.Value.HasFlag(InstanceManagerRights.List); IQueryable QueryForUser() { var query = DatabaseContext @@ -619,8 +616,8 @@ public async ValueTask GetId(long id, CancellationToken cancellat if (ValidateInstanceOnlineStatus(instance)) await DatabaseContext.Save(cancellationToken); - if (cantList && !instance.InstancePermissionSets.Any(instanceUser => instanceUser.PermissionSetId == AuthenticationContext.PermissionSet.Id.Value && - (instanceUser.RepositoryRights != RepositoryRights.None || + if (cantList && !instance.InstancePermissionSets.Any(instanceUser => instanceUser.PermissionSetId == AuthenticationContext.PermissionSet.Require(x => x.Id) + && (instanceUser.RepositoryRights != RepositoryRights.None || instanceUser.EngineRights != EngineRights.None || instanceUser.ChatBotRights != ChatBotRights.None || instanceUser.ConfigurationRights != ConfigurationRights.None || @@ -633,8 +630,8 @@ public async ValueTask GetId(long id, CancellationToken cancellat var moveJob = await QueryForUser() .SelectMany(x => x.Jobs) - .Where(x => !x.StoppedAt.HasValue && x.Description.StartsWith(MoveInstanceJobPrefix)) - .Include(x => x.StartedBy) + .Where(x => !x.StoppedAt.HasValue && x.JobCode == JobCode.Move) + .Include(x => x.StartedBy!) .ThenInclude(x => x.CreatedBy) .Include(x => x.Instance) .FirstOrDefaultAsync(cancellationToken); @@ -664,7 +661,7 @@ public async ValueTask GrantPermissions(long id, CancellationToke // ensure the current user has write privilege on the instance var usersInstancePermissionSet = await BaseQuery() .SelectMany(x => x.InstancePermissionSets) - .Where(x => x.PermissionSetId == AuthenticationContext.PermissionSet.Id.Value) + .Where(x => x.PermissionSetId == AuthenticationContext.PermissionSet.Id) .FirstOrDefaultAsync(cancellationToken); if (usersInstancePermissionSet == default) { @@ -693,7 +690,7 @@ public async ValueTask GrantPermissions(long id, CancellationToke /// The . /// The for the operation. /// A resulting in the new or if ports could not be allocated. - async ValueTask CreateDefaultInstance(InstanceCreateRequest initialSettings, CancellationToken cancellationToken) + async ValueTask CreateDefaultInstance(InstanceCreateRequest initialSettings, CancellationToken cancellationToken) { var ddPort = await portAllocator.GetAvailablePort(1024, false, cancellationToken); if (!ddPort.HasValue) @@ -773,12 +770,12 @@ public async ValueTask GrantPermissions(long id, CancellationToke /// /// An optional existing to update. /// or a new with full rights. - InstancePermissionSet InstanceAdminPermissionSet(InstancePermissionSet permissionSetToModify) + InstancePermissionSet InstanceAdminPermissionSet(InstancePermissionSet? permissionSetToModify) { permissionSetToModify ??= new InstancePermissionSet() { PermissionSet = AuthenticationContext.PermissionSet, - PermissionSetId = AuthenticationContext.PermissionSet.Id.Value, + PermissionSetId = AuthenticationContext.PermissionSet.Require(x => x.Id), }; permissionSetToModify.EngineRights = RightsHelper.AllRights(); permissionSetToModify.ChatBotRights = RightsHelper.AllRights(); @@ -795,7 +792,8 @@ InstancePermissionSet InstanceAdminPermissionSet(InstancePermissionSet permissio /// /// The path to normalize. /// The normalized . - string NormalizePath(string path) + [return: NotNullIfNotNull(nameof(path))] + string? NormalizePath(string? path) { if (path == null) return null; From e02aff71d1b5cb3fbc9b5dd3c028182bcd9b693c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:44:50 -0500 Subject: [PATCH 552/717] Nullify `InstancePermissionSetController` --- .../InstancePermissionSetController.cs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs index d5d4a0fb79f..d86f0b7877b 100644 --- a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs @@ -22,8 +22,6 @@ using Z.EntityFramework.Plus; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -117,7 +115,7 @@ public async ValueTask Create([FromBody] InstancePermissionSetReq RepositoryRights = RightsHelper.Clamp(model.RepositoryRights ?? RepositoryRights.None), InstancePermissionSetRights = RightsHelper.Clamp(model.InstancePermissionSetRights ?? InstancePermissionSetRights.None), PermissionSetId = model.PermissionSetId, - InstanceId = Instance.Id.Value, + InstanceId = Instance.Require(x => x.Id), }; DatabaseContext.InstancePermissionSets.Add(dbUser); @@ -158,16 +156,16 @@ public async ValueTask Update([FromBody] InstancePermissionSetReq if (originalPermissionSet == null) return this.Gone(); - originalPermissionSet.EngineRights = RightsHelper.Clamp(model.EngineRights ?? originalPermissionSet.EngineRights.Value); - originalPermissionSet.RepositoryRights = RightsHelper.Clamp(model.RepositoryRights ?? originalPermissionSet.RepositoryRights.Value); - originalPermissionSet.InstancePermissionSetRights = RightsHelper.Clamp(model.InstancePermissionSetRights ?? originalPermissionSet.InstancePermissionSetRights.Value); - originalPermissionSet.ChatBotRights = RightsHelper.Clamp(model.ChatBotRights ?? originalPermissionSet.ChatBotRights.Value); - originalPermissionSet.ConfigurationRights = RightsHelper.Clamp(model.ConfigurationRights ?? originalPermissionSet.ConfigurationRights.Value); - originalPermissionSet.DreamDaemonRights = RightsHelper.Clamp(model.DreamDaemonRights ?? originalPermissionSet.DreamDaemonRights.Value); - originalPermissionSet.DreamMakerRights = RightsHelper.Clamp(model.DreamMakerRights ?? originalPermissionSet.DreamMakerRights.Value); + originalPermissionSet.EngineRights = RightsHelper.Clamp(model.EngineRights ?? originalPermissionSet.EngineRights!.Value); + originalPermissionSet.RepositoryRights = RightsHelper.Clamp(model.RepositoryRights ?? originalPermissionSet.RepositoryRights!.Value); + originalPermissionSet.InstancePermissionSetRights = RightsHelper.Clamp(model.InstancePermissionSetRights ?? originalPermissionSet.InstancePermissionSetRights!.Value); + originalPermissionSet.ChatBotRights = RightsHelper.Clamp(model.ChatBotRights ?? originalPermissionSet.ChatBotRights!.Value); + originalPermissionSet.ConfigurationRights = RightsHelper.Clamp(model.ConfigurationRights ?? originalPermissionSet.ConfigurationRights!.Value); + originalPermissionSet.DreamDaemonRights = RightsHelper.Clamp(model.DreamDaemonRights ?? originalPermissionSet.DreamDaemonRights!.Value); + originalPermissionSet.DreamMakerRights = RightsHelper.Clamp(model.DreamMakerRights ?? originalPermissionSet.DreamMakerRights!.Value); await DatabaseContext.Save(cancellationToken); - var showFullPermissionSet = originalPermissionSet.PermissionSetId == AuthenticationContext.PermissionSet.Id.Value + var showFullPermissionSet = originalPermissionSet.PermissionSetId == AuthenticationContext.PermissionSet.Require(x => x.Id) || (AuthenticationContext.GetRight(RightsType.InstancePermissionSet) & (ulong)InstancePermissionSetRights.Read) != 0; return Json( showFullPermissionSet @@ -186,7 +184,7 @@ public async ValueTask Update([FromBody] InstancePermissionSetReq [HttpGet] [TgsAuthorize] [ProducesResponseType(typeof(InstancePermissionSetResponse), 200)] - public IActionResult Read() => Json(AuthenticationContext.InstancePermissionSet.ToApi()); + public IActionResult Read() => Json(InstancePermissionSet.ToApi()); /// /// Lists s for the instance. From 83d07d5071bb41d280ed8e108924d9626faf0c52 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:45:18 -0500 Subject: [PATCH 553/717] Clean up a `ValueTask` message --- .../Components/Engine/TestOpenDreamInstaller.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs index 30d995f99c1..f5d158259c0 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs @@ -53,7 +53,7 @@ static async Task RepoDownloadTest(bool needsClone) true, It.IsAny())) .Callback(() => ++cloneAttempts) - .Returns(ValueTask.FromResult(needsClone ? mockRepository.Object : null)) + .ReturnsAsync(needsClone ? mockRepository.Object : null) .Verifiable(Times.Exactly(1)); mockRepositoryManager.Setup(x => x.LoadRepository( From 5031d54ea21b2581810144cbd8f725de8c478bf4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:47:15 -0500 Subject: [PATCH 554/717] Nullify `InstanceRequiredController` --- .../Controllers/InstanceRequiredController.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs b/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs index 1e36f544b43..f3a6ff9bdcd 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceRequiredController.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// From 665868b1dffe935ef8071a1857e834bd55e1ddd6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:47:58 -0500 Subject: [PATCH 555/717] Nullify `JobController` --- src/Tgstation.Server.Host/Controllers/JobController.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/JobController.cs b/src/Tgstation.Server.Host/Controllers/JobController.cs index 6019223426e..2b9f1b15f1a 100644 --- a/src/Tgstation.Server.Host/Controllers/JobController.cs +++ b/src/Tgstation.Server.Host/Controllers/JobController.cs @@ -19,8 +19,6 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -81,7 +79,7 @@ public ValueTask Read([FromQuery] int? page, [FromQuery] int? pag .Include(x => x.StartedBy) .Include(x => x.CancelledBy) .Include(x => x.Instance) - .Where(x => x.Instance.Id == Instance.Id && !x.StoppedAt.HasValue) + .Where(x => x.Instance!.Id == Instance.Id && !x.StoppedAt.HasValue) .OrderByDescending(x => x.StartedAt))), AddJobProgressResponseTransformer, page, @@ -109,7 +107,7 @@ public ValueTask List([FromQuery] int? page, [FromQuery] int? pag .Include(x => x.StartedBy) .Include(x => x.CancelledBy) .Include(x => x.Instance) - .Where(x => x.Instance.Id == Instance.Id) + .Where(x => x.Instance!.Id == Instance.Id) .OrderByDescending(x => x.StartedAt))), AddJobProgressResponseTransformer, page, @@ -137,7 +135,7 @@ public async ValueTask Delete(long id, CancellationToken cancella .AsQueryable() .Include(x => x.StartedBy) .Include(x => x.Instance) - .Where(x => x.Id == id && x.Instance.Id == Instance.Id) + .Where(x => x.Id == id && x.Instance!.Id == Instance.Id) .FirstOrDefaultAsync(cancellationToken); if (job == default) return NotFound(); @@ -169,7 +167,7 @@ public async ValueTask GetId(long id, CancellationToken cancellat var job = await DatabaseContext .Jobs .AsQueryable() - .Where(x => x.Id == id && x.Instance.Id == Instance.Id) + .Where(x => x.Id == id && x.Instance!.Id == Instance.Id) .Include(x => x.StartedBy) .Include(x => x.CancelledBy) .Include(x => x.Instance) From 0e34a666267ce80ec3465c6f68699c2008e85549 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:50:04 -0500 Subject: [PATCH 556/717] Nullify `RepositoryController` --- .../Controllers/RepositoryController.cs | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs index dbf80a4171e..dcff26b25e7 100644 --- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs +++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs @@ -24,8 +24,6 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -213,7 +211,7 @@ public async ValueTask Delete(CancellationToken cancellationToken await DatabaseContext.Save(cancellationToken); - Logger.LogInformation("Instance {instanceId} repository delete initiated by user {userId}", Instance.Id, AuthenticationContext.User.Id.Value); + Logger.LogInformation("Instance {instanceId} repository delete initiated by user {userId}", Instance.Id, AuthenticationContext.User.Require(x => x.Id)); var job = Job.Create(JobCode.RepositoryDelete, AuthenticationContext.User, Instance); var api = currentModel.ToApi(); @@ -378,23 +376,23 @@ bool CheckModified(Expression var api = canRead ? currentModel.ToApi() : new RepositoryResponse(); if (canRead) { - var earlyOut = await WithComponentInstance( - async instance => - { - var repoManager = instance.RepositoryManager; - if (repoManager.CloneInProgress) - return Conflict(new ErrorMessageResponse(ErrorCode.RepoCloning)); + var earlyOut = await WithComponentInstanceNullable( + async instance => + { + var repoManager = instance.RepositoryManager; + if (repoManager.CloneInProgress) + return Conflict(new ErrorMessageResponse(ErrorCode.RepoCloning)); - if (repoManager.InUse) - return Conflict(new ErrorMessageResponse(ErrorCode.RepoBusy)); + if (repoManager.InUse) + return Conflict(new ErrorMessageResponse(ErrorCode.RepoBusy)); - using var repo = await repoManager.LoadRepository(cancellationToken); - if (repo == null) - return Conflict(new ErrorMessageResponse(ErrorCode.RepoMissing)); - await PopulateApi(api, repo, DatabaseContext, Instance, cancellationToken); + using var repo = await repoManager.LoadRepository(cancellationToken); + if (repo == null) + return Conflict(new ErrorMessageResponse(ErrorCode.RepoMissing)); + await PopulateApi(api, repo, DatabaseContext, Instance, cancellationToken); - return null; - }); + return null; + }); if (earlyOut != null) return earlyOut; @@ -404,7 +402,7 @@ bool CheckModified(Expression await DatabaseContext.Save(cancellationToken); // format the job description - string description = null; + string? description = null; if (model.UpdateFromOrigin == true) if (model.Reference != null) description = String.Format(CultureInfo.InvariantCulture, "Fetch and hard reset repository to origin/{0}", model.Reference); @@ -424,7 +422,7 @@ bool CheckModified(Expression : "T", String.Join( ", ", - model.NewTestMerges.Select( + model.NewTestMerges!.Select( x => String.Format( CultureInfo.InvariantCulture, "#{0}{1}", @@ -450,7 +448,7 @@ bool CheckModified(Expression currentModel, AuthenticationContext.User, loggerFactory.CreateLogger(), - Instance.Id.Value); + Instance.Require(x => x.Id)); // Time to access git, do it in a job await jobManager.RegisterOperation( @@ -486,16 +484,14 @@ async ValueTask PopulateApi( apiResponse.Reference = repository.Reference; // rev info stuff - Models.RevisionInformation revisionInfo = null; var needsDbUpdate = await RepositoryUpdateService.LoadRevisionInformation( repository, databaseContext, Logger, instance, null, - newRevInfo => revisionInfo = newRevInfo, + newRevInfo => apiResponse.RevisionInformation = newRevInfo.ToApi(), cancellationToken); - apiResponse.RevisionInformation = revisionInfo.ToApi(); return needsDbUpdate; } } From ee0953ba81df24eef5723b4db557731f4392831e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:51:05 -0500 Subject: [PATCH 557/717] Nullify `RootController` --- src/Tgstation.Server.Host/Controllers/RootController.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/RootController.cs b/src/Tgstation.Server.Host/Controllers/RootController.cs index ffc7f050299..9ae6e7e9425 100644 --- a/src/Tgstation.Server.Host/Controllers/RootController.cs +++ b/src/Tgstation.Server.Host/Controllers/RootController.cs @@ -12,8 +12,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -106,7 +104,7 @@ public IActionResult Index() else return Redirect(ApiDocumentationRoute); - Dictionary links; + Dictionary? links; if (panelEnabled) links = new Dictionary() { @@ -136,7 +134,7 @@ public IActionResult GetLogo() ? LogoSvgWindowsName : LogoSvgLinuxName; - return (IActionResult)this.TryServeFile(hostEnvironment, logger, $"{logoFileName}.svg") ?? NotFound(); + return (IActionResult?)this.TryServeFile(hostEnvironment, logger, $"{logoFileName}.svg") ?? NotFound(); } } } From d615983a70133843f0928bdbc4003a6008f83702 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:56:57 -0500 Subject: [PATCH 558/717] Nullify `SwarmController` --- .../Controllers/SwarmController.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/SwarmController.cs b/src/Tgstation.Server.Host/Controllers/SwarmController.cs index c56cfaa5c8a..be171b19d8b 100644 --- a/src/Tgstation.Server.Host/Controllers/SwarmController.cs +++ b/src/Tgstation.Server.Host/Controllers/SwarmController.cs @@ -19,8 +19,6 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -34,7 +32,7 @@ public sealed class SwarmController : ApiControllerBase /// /// Get the current registration from the . /// - internal Guid RequestRegistrationId => Guid.Parse(Request.Headers[SwarmConstants.RegistrationIdHeader].First()); + internal Guid RequestRegistrationId => Guid.Parse(Request.Headers[SwarmConstants.RegistrationIdHeader].First()!); /// /// The for the . @@ -152,6 +150,9 @@ public IActionResult UpdateNodeList([FromBody] SwarmServersUpdateRequest servers { ArgumentNullException.ThrowIfNull(serversUpdateRequest); + if (serversUpdateRequest.SwarmServers == null) + return BadRequest(); + if (!ValidateRegistration()) return Forbid(); @@ -212,7 +213,7 @@ public async ValueTask AbortUpdate() } /// - protected override async ValueTask HookExecuteAction(Func executeAction, CancellationToken cancellationToken) + protected override async ValueTask HookExecuteAction(Func executeAction, CancellationToken cancellationToken) { using (LogContext.PushProperty(SerilogContextHelper.RequestPathContextProperty, $"{Request.Method} {Request.Path}")) { @@ -243,7 +244,7 @@ protected override async ValueTask HookExecuteAction(Func e if (ModelState?.IsValid == false) { var errorMessages = ModelState - .SelectMany(x => x.Value.Errors) + .SelectMany(x => x.Value!.Errors) .Select(x => x.ErrorMessage); logger.LogDebug( From a2d2123fe08e3b8e9db77799ac148381e900b090 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 14:57:18 -0500 Subject: [PATCH 559/717] Nullify `TransferController` --- src/Tgstation.Server.Host/Controllers/TransferController.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/TransferController.cs b/src/Tgstation.Server.Host/Controllers/TransferController.cs index 07feea08a0b..8a0a2ebcd3f 100644 --- a/src/Tgstation.Server.Host/Controllers/TransferController.cs +++ b/src/Tgstation.Server.Host/Controllers/TransferController.cs @@ -16,8 +16,6 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// From 1b95ded829e8f182bbf9f6e396603f69263f8b64 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 15:03:02 -0500 Subject: [PATCH 560/717] Nullify `UserController` And fix some `.Any()`/`.Count` issues. --- .../Controllers/UserController.cs | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/UserController.cs b/src/Tgstation.Server.Host/Controllers/UserController.cs index 8eed28d3f54..68bccfa1692 100644 --- a/src/Tgstation.Server.Host/Controllers/UserController.cs +++ b/src/Tgstation.Server.Host/Controllers/UserController.cs @@ -22,8 +22,6 @@ using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -105,7 +103,7 @@ public async ValueTask Create([FromBody] UserCreateRequest model, return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); if ((model.Password != null && model.SystemIdentifier != null) - || (model.Password == null && model.SystemIdentifier == null && model.OAuthConnections?.Any() != true)) + || (model.Password == null && model.SystemIdentifier == null && (model.OAuthConnections?.Count > 0) != true)) return BadRequest(new ErrorMessageResponse(ErrorCode.UserMismatchPasswordSid)); if (model.Group != null && model.PermissionSet != null) @@ -146,14 +144,14 @@ public async ValueTask Create([FromBody] UserCreateRequest model, { return RequiresPosixSystemIdentity(ex); } - else if (!(model.Password?.Length == 0 && model.OAuthConnections?.Any() == true)) + else if (!(model.Password?.Length == 0 && (model.OAuthConnections?.Count > 0) == true)) { - var result = TrySetPassword(dbUser, model.Password, true); + var result = TrySetPassword(dbUser, model.Password!, true); if (result != null) return result; } - dbUser.CanonicalName = Models.User.CanonicalizeName(dbUser.Name); + dbUser.CanonicalName = Models.User.CanonicalizeName(dbUser.Name!); DatabaseContext.Users.Add(dbUser); @@ -206,7 +204,7 @@ public async ValueTask Update([FromBody] UserUpdateRequest model, .Where(x => x.Id == model.Id) .Include(x => x.CreatedBy) .Include(x => x.OAuthConnections) - .Include(x => x.Group) + .Include(x => x.Group!) .ThenInclude(x => x.PermissionSet) .Include(x => x.PermissionSet) .FirstOrDefaultAsync(cancellationToken); @@ -256,7 +254,7 @@ public async ValueTask Update([FromBody] UserUpdateRequest model, bool userWasDisabled; if (model.Enabled.HasValue) { - userWasDisabled = originalUser.Enabled.Value && !model.Enabled.Value; + userWasDisabled = originalUser.Require(x => x.Enabled) && !model.Enabled.Value; if (userWasDisabled) originalUser.LastPasswordUpdate = DateTimeOffset.UtcNow; @@ -266,7 +264,7 @@ public async ValueTask Update([FromBody] UserUpdateRequest model, userWasDisabled = false; if (model.OAuthConnections != null - && (model.OAuthConnections.Count != originalUser.OAuthConnections.Count + && (model.OAuthConnections.Count != originalUser.OAuthConnections!.Count || !model.OAuthConnections.All(x => originalUser.OAuthConnections.Any(y => y.Provider == x.Provider && y.ExternalUserId == x.ExternalUserId)))) { if (originalUser.CanonicalName == Models.User.CanonicalizeName(DefaultCredentials.AdminUserName)) @@ -374,7 +372,7 @@ public ValueTask List([FromQuery] int? page, [FromQuery] int? pag .Include(x => x.CreatedBy) .Include(x => x.PermissionSet) .Include(x => x.OAuthConnections) - .Include(x => x.Group) + .Include(x => x.Group!) .ThenInclude(x => x.PermissionSet) .OrderBy(x => x.Id))), null, @@ -407,7 +405,7 @@ public async ValueTask GetId(long id, CancellationToken cancellat .Where(x => x.Id == id) .Include(x => x.CreatedBy) .Include(x => x.OAuthConnections) - .Include(x => x.Group) + .Include(x => x.Group!) .ThenInclude(x => x.PermissionSet) .Include(x => x.PermissionSet) .FirstOrDefaultAsync(cancellationToken); @@ -428,8 +426,8 @@ public async ValueTask GetId(long id, CancellationToken cancellat /// A resulting in a new on success, if the requested did not exist. async ValueTask CreateNewUserFromModel(Api.Models.Internal.UserApiBase model, CancellationToken cancellationToken) { - Models.PermissionSet permissionSet = null; - UserGroup group = null; + Models.PermissionSet? permissionSet = null; + UserGroup? group = null; if (model.Group != null) group = await DatabaseContext .Groups @@ -471,7 +469,7 @@ async ValueTask CreateNewUserFromModel(Api.Models.Internal.UserApiBase mod /// The to check. /// If this is a new . /// if is valid, a otherwise. - BadRequestObjectResult CheckValidName(UserUpdateRequest model, bool newUser) + BadRequestObjectResult? CheckValidName(UserUpdateRequest model, bool newUser) { var userInvalidWithNullName = newUser && model.Name == null && model.SystemIdentifier == null; if (userInvalidWithNullName || (model.Name != null && String.IsNullOrWhiteSpace(model.Name))) @@ -490,7 +488,7 @@ BadRequestObjectResult CheckValidName(UserUpdateRequest model, bool newUser) /// The new password. /// If this is for a new . /// on success, if is too short. - BadRequestObjectResult TrySetPassword(User dbUser, string newPassword, bool newUser) + BadRequestObjectResult? TrySetPassword(User dbUser, string newPassword, bool newUser) { newPassword ??= String.Empty; if (newPassword.Length < generalConfiguration.MinimumPasswordLength) From c08e84a38a52a3894b2e6cad37c01a5a092b9333 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 15:04:44 -0500 Subject: [PATCH 561/717] Nullify `UserGroupController` --- .../Controllers/UserGroupController.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Controllers/UserGroupController.cs b/src/Tgstation.Server.Host/Controllers/UserGroupController.cs index d50bc8e9c51..b6f48b81976 100644 --- a/src/Tgstation.Server.Host/Controllers/UserGroupController.cs +++ b/src/Tgstation.Server.Host/Controllers/UserGroupController.cs @@ -23,8 +23,6 @@ using Z.EntityFramework.Plus; -#nullable disable - namespace Tgstation.Server.Host.Controllers { /// @@ -133,7 +131,7 @@ public async ValueTask Update([FromBody] UserGroupUpdateRequest m if (model.PermissionSet != null) { - currentGroup.PermissionSet.AdministrationRights = model.PermissionSet.AdministrationRights ?? currentGroup.PermissionSet.AdministrationRights; + currentGroup.PermissionSet!.AdministrationRights = model.PermissionSet.AdministrationRights ?? currentGroup.PermissionSet.AdministrationRights; currentGroup.PermissionSet.InstanceManagerRights = model.PermissionSet.InstanceManagerRights ?? currentGroup.PermissionSet.InstanceManagerRights; } @@ -141,7 +139,7 @@ public async ValueTask Update([FromBody] UserGroupUpdateRequest m await DatabaseContext.Save(cancellationToken); - if (!AuthenticationContext.PermissionSet.AdministrationRights.Value.HasFlag(AdministrationRights.ReadUsers)) + if (!AuthenticationContext.PermissionSet.AdministrationRights!.Value.HasFlag(AdministrationRights.ReadUsers)) return Json(new UserGroupResponse { Id = currentGroup.Id, @@ -222,7 +220,7 @@ public async ValueTask Delete(long id, CancellationToken cancella var numDeleted = await DatabaseContext .Groups .AsQueryable() - .Where(x => x.Id == id && x.Users.Count == 0) + .Where(x => x.Id == id && x.Users!.Count == 0) .DeleteAsync(cancellationToken); if (numDeleted > 0) From 2cc1014ab615a390ed581660382bae9f9f77d0f0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 15:06:37 -0500 Subject: [PATCH 562/717] Handle HTTP error case with OD graceful shutdowns --- .../Engine/OpenDreamInstallation.cs | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index 7e1fc27e47c..afc32931e4f 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -144,25 +144,33 @@ public override async ValueTask StopServerProcess( request.Method = HttpMethod.Post; var responseTask = httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken); - - await Task.WhenAny(timeout, lifetime, responseTask); - if (responseTask.IsCompleted) + try { - using var response = await responseTask; - if (response.IsSuccessStatusCode) + await Task.WhenAny(timeout, lifetime, responseTask); + if (responseTask.IsCompleted) { - logger.LogDebug("Robust.Server responded to the shutdown command successfully. Waiting for exit..."); - await Task.WhenAny(timeout, lifetime); + using var response = await responseTask; + if (response.IsSuccessStatusCode) + { + logger.LogDebug("Robust.Server responded to the shutdown command successfully. Waiting for exit..."); + await Task.WhenAny(timeout, lifetime); + } } + + if (!lifetime.IsCompleted) + logger.LogWarning("Robust.Server graceful exit timed out!"); + } + catch (HttpRequestException ex) + { + logger.LogDebug(ex, "Unable to send graceful exit request to Robust.Server watchdog API!"); } if (lifetime.IsCompleted) { - logger.LogTrace("Robust.Server gracefully exited"); + logger.LogTrace("Robust.Server exited without termination"); return; } - logger.LogWarning("Robust.Server graceful exit timed out!"); await base.StopServerProcess(logger, process, accessIdentifier, port, cancellationToken); } } From 34f142868c083a6e0aaa279cc085a5a270d36fd9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 16:36:36 -0500 Subject: [PATCH 563/717] Fix engine installs not respecting `Session:LowPriorityDeploymentProcesses` --- .../Components/Engine/OpenDreamInstaller.cs | 14 +++++++++++++- .../Components/Engine/WindowsByondInstaller.cs | 9 +++++++++ .../Components/Engine/WindowsOpenDreamInstaller.cs | 6 +++++- .../System/WindowsFirewallHelper.cs | 5 +++++ .../Components/Engine/TestOpenDreamInstaller.cs | 6 +++++- .../Live/Instance/EngineTest.cs | 1 + .../Live/Instance/InstanceTest.cs | 4 +++- tests/Tgstation.Server.Tests/TestVersions.cs | 2 ++ 8 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 886b419a3e5..c5f03e1e329 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -59,6 +59,11 @@ class OpenDreamInstaller : EngineInstallerBase /// protected GeneralConfiguration GeneralConfiguration { get; } + /// + /// The for the . + /// + protected SessionConfiguration SessionConfiguration { get; } + /// /// The for the . /// @@ -90,6 +95,7 @@ class OpenDreamInstaller : EngineInstallerBase /// The value of . /// The value of . /// The containing value of . + /// The containing value of . public OpenDreamInstaller( IIOManager ioManager, ILogger logger, @@ -98,7 +104,8 @@ public OpenDreamInstaller( IRepositoryManager repositoryManager, IAsyncDelayer asyncDelayer, IAbstractHttpClientFactory httpClientFactory, - IOptions generalConfigurationOptions) + IOptions generalConfigurationOptions, + IOptions sessionConfigurationOptions) : base(ioManager, logger) { this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); @@ -107,6 +114,7 @@ public OpenDreamInstaller( this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); GeneralConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); + SessionConfiguration = sessionConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(sessionConfigurationOptions)); } /// @@ -254,6 +262,10 @@ await HandleExtremelyLongPathOperation( null, !GeneralConfiguration.OpenDreamSuppressInstallOutput, !GeneralConfiguration.OpenDreamSuppressInstallOutput); + + if (SessionConfiguration.LowPriorityDeploymentProcesses) + buildProcess.AdjustPriority(false); + using (cancellationToken.Register(() => buildProcess.Terminate())) buildExitCode = await buildProcess.Lifetime; diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index e24a77a261e..4020ed97cf5 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -73,6 +73,11 @@ sealed class WindowsByondInstaller : ByondInstallerBase, IDisposable /// readonly GeneralConfiguration generalConfiguration; + /// + /// The for the . + /// + readonly SessionConfiguration sessionConfiguration; + /// /// The for the . /// @@ -88,6 +93,7 @@ sealed class WindowsByondInstaller : ByondInstallerBase, IDisposable /// /// The value of . /// The containing the value of . + /// The containing the value of . /// The for the . /// The for the . /// The for the . @@ -96,11 +102,13 @@ public WindowsByondInstaller( IIOManager ioManager, IFileDownloader fileDownloader, IOptions generalConfigurationOptions, + IOptions sessionConfigurationOptions, ILogger logger) : base(ioManager, logger, fileDownloader) { this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); + sessionConfiguration = sessionConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(sessionConfigurationOptions)); var documentsDirectory = Environment.GetFolderPath( Environment.SpecialFolder.MyDocuments, @@ -253,6 +261,7 @@ async ValueTask AddDreamDaemonToFirewall(EngineVersion version, string path, Can Logger, ruleName, dreamDaemonPath, + sessionConfiguration.LowPriorityDeploymentProcesses, cancellationToken); } catch (Exception ex) diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index 2fb12e80def..d343c32802f 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -40,6 +40,7 @@ sealed class WindowsOpenDreamInstaller : OpenDreamInstaller /// The for the . /// The for the . /// The of for the . + /// The of for the . /// The value of . public WindowsOpenDreamInstaller( IIOManager ioManager, @@ -50,6 +51,7 @@ public WindowsOpenDreamInstaller( IAsyncDelayer asyncDelayer, IAbstractHttpClientFactory httpClientFactory, IOptions generalConfigurationOptions, + IOptions sessionConfigurationOptions, IFilesystemLinkFactory linkFactory) : base( ioManager, @@ -59,7 +61,8 @@ public WindowsOpenDreamInstaller( repositoryManager, asyncDelayer, httpClientFactory, - generalConfigurationOptions) + generalConfigurationOptions, + sessionConfigurationOptions) { this.linkFactory = linkFactory ?? throw new ArgumentNullException(nameof(linkFactory)); } @@ -122,6 +125,7 @@ async ValueTask AddServerFirewallException(EngineVersion version, string path, C Logger, ruleName, serverExePath, + SessionConfiguration.LowPriorityDeploymentProcesses, cancellationToken); } catch (Exception ex) diff --git a/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs b/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs index 74964a5569f..fff15210927 100644 --- a/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs +++ b/src/Tgstation.Server.Host/System/WindowsFirewallHelper.cs @@ -18,6 +18,7 @@ static class WindowsFirewallHelper /// The to write to. /// The name of the rule in Windows Firewall. /// The path to the .exe to add a firewall exception for. + /// If the "netsh.exe" process should be run with lower process priority. /// The for the operation. /// A resulting in the exit code of the call to netsh.exe. public static async ValueTask AddFirewallException( @@ -25,6 +26,7 @@ public static async ValueTask AddFirewallException( ILogger logger, string exceptionName, string exePath, + bool lowPriority, CancellationToken cancellationToken) { logger.LogInformation("Adding Windows Firewall exception for {path}...", exePath); @@ -36,6 +38,9 @@ public static async ValueTask AddFirewallException( readStandardHandles: true, noShellExecute: true); + if (lowPriority) + netshProcess.AdjustPriority(false); + int exitCode; using (cancellationToken.Register(() => netshProcess.Terminate())) exitCode = (await netshProcess.Lifetime).Value; diff --git a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs index f5d158259c0..2a62fea29ad 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs @@ -37,8 +37,11 @@ static async Task RepoDownloadTest(bool needsClone) { var mockGeneralConfigOptions = new Mock>(); var generalConfig = new GeneralConfiguration(); + var mockSessionConfigOptions = new Mock>(); + var sessionConfig = new SessionConfiguration(); Assert.IsNotNull(generalConfig.OpenDreamGitUrl); mockGeneralConfigOptions.SetupGet(x => x.Value).Returns(generalConfig); + mockSessionConfigOptions.SetupGet(x => x.Value).Returns(sessionConfig); var cloneAttempts = 0; var mockRepository = new Mock(); @@ -73,7 +76,8 @@ static async Task RepoDownloadTest(bool needsClone) mockRepositoryManager.Object, Mock.Of(), Mock.Of(), - mockGeneralConfigOptions.Object); + mockGeneralConfigOptions.Object, + mockSessionConfigOptions.Object); var data = await installer.DownloadVersion( new EngineVersion diff --git a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs index 57c4255130b..626f9628c39 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs @@ -302,6 +302,7 @@ async Task TestCustomInstalls(CancellationToken cancellationToken) Mock.Of(), fileDownloader, generalConfigOptionsMock.Object, + sessionConfigOptionsMock.Object, Mock.Of>()) : new PosixByondInstaller( Mock.Of(), diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 76bfa30b234..bbe349ca5c8 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -120,13 +120,15 @@ public static async ValueTask DownloadEngineVersion( genConfig), Mock.Of(), Mock.Of(), - mockOptions.Object) + mockOptions.Object, + Options.Create(new SessionConfiguration())) : new PlatformIdentifier().IsWindows ? new WindowsByondInstaller( Mock.Of(), Mock.Of(), fileDownloader, Options.Create(genConfig), + Options.Create(new SessionConfiguration()), Mock.Of>()) : new PosixByondInstaller( Mock.Of(), diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 34dad9e0066..01fdf2d0ec1 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -126,6 +126,7 @@ await CachingFileDownloader.InitializeByondVersion( Mock.Of(), new CachingFileDownloader(Mock.Of>()), mockGeneralConfigurationOptions.Object, + mockSessionConfigurationOptions.Object, Mock.Of>()); const string ArchiveEntryPath = "byond/bin/dd.exe"; @@ -193,6 +194,7 @@ await CachingFileDownloader.InitializeByondVersion( Mock.Of(), fileDownloader, mockGeneralConfigurationOptions.Object, + mockSessionConfigurationOptions.Object, loggerFactory.CreateLogger()) : new PosixByondInstaller( new PosixPostWriteHandler(loggerFactory.CreateLogger()), From 022b374a449dccc00abd0ec6d844d969ca25f724 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 16:38:49 -0500 Subject: [PATCH 564/717] Fix some IDE messages --- .../Components/Engine/WindowsByondInstaller.cs | 11 ++++++++--- .../Live/Instance/EngineTest.cs | 15 +++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 4020ed97cf5..2c3aad65bc8 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -130,14 +130,19 @@ public override ValueTask Install(EngineVersion version, string path, Cancellati CheckVersionValidity(version); ArgumentNullException.ThrowIfNull(path); + var noPromptTrustedTask = SetNoPromptTrusted(path, cancellationToken); + var installDirectXTask = InstallDirectX(path, cancellationToken); var tasks = new List(3) { - SetNoPromptTrusted(path, cancellationToken), - InstallDirectX(path, cancellationToken), + noPromptTrustedTask, + installDirectXTask, }; if (!generalConfiguration.SkipAddingByondFirewallException) - tasks.Add(AddDreamDaemonToFirewall(version, path, cancellationToken)); + { + var firewallTask = AddDreamDaemonToFirewall(version, path, cancellationToken); + tasks.Add(firewallTask); + } return ValueTaskExtensions.WhenAll(tasks); } diff --git a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs index 626f9628c39..a2f82495448 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/EngineTest.cs @@ -134,17 +134,12 @@ ValueTask TestInstallNullVersion(CancellationToken cancellationToken) cancellationToken), ErrorCode.ModelValidationFailure); public static int EngineInstallationTimeout(EngineVersion testVersion) - { - switch (testVersion.Engine.Value) + => testVersion.Engine.Value switch { - case EngineType.Byond: - return 30; - case EngineType.OpenDream: - return 500; - default: - throw new InvalidOperationException($"Unknown engine type: {testVersion.Engine.Value}"); - } - } + EngineType.Byond => 30, + EngineType.OpenDream => 500, + _ => throw new InvalidOperationException($"Unknown engine type: {testVersion.Engine.Value}"), + }; int EngineInstallationTimeout() => EngineInstallationTimeout(testVersion); From 79e76282367e7a11dd0ae3db031226a95a6a5e4f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 21:59:04 -0500 Subject: [PATCH 565/717] Cleanup OpenDream graceful shutdown handling --- .../Engine/EngineInstallationBase.cs | 1 + .../Engine/OpenDreamInstallation.cs | 63 +++++++++++-------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs index f2da09f3459..bbf809ee253 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs @@ -71,6 +71,7 @@ public abstract string FormatServerArguments( /// public virtual async ValueTask StopServerProcess(ILogger logger, IProcess process, string accessIdentifier, ushort port, CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); logger.LogTrace("Terminating engine server process..."); process.Terminate(); await process.Lifetime; diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index afc32931e4f..c16e25c9a18 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Net.Http; using System.Net.Http.Headers; using System.Net.Mime; @@ -133,42 +134,50 @@ public override async ValueTask StopServerProcess( var timeout = asyncDelayer.Delay(TimeSpan.FromSeconds(MaximumTerminationSeconds), cancellationToken); var lifetime = process.Lifetime; - using var httpClient = httpClientFactory.CreateClient(); - using var request = new HttpRequestMessage(); - request.Headers.Add("WatchdogToken", accessIdentifier); - request.RequestUri = new Uri($"http://localhost:{port}/shutdown"); - request.Content = new StringContent( - "{\"Reason\":\"TGS session termination\"}", - Encoding.UTF8, - new MediaTypeHeaderValue(MediaTypeNames.Application.Json)); - request.Method = HttpMethod.Post; - - var responseTask = httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken); + var stopwatch = Stopwatch.StartNew(); try { - await Task.WhenAny(timeout, lifetime, responseTask); - if (responseTask.IsCompleted) + using var httpClient = httpClientFactory.CreateClient(); + using var request = new HttpRequestMessage(); + request.Headers.Add("WatchdogToken", accessIdentifier); + request.RequestUri = new Uri($"http://localhost:{port}/shutdown"); + request.Content = new StringContent( + "{\"Reason\":\"TGS session termination\"}", + Encoding.UTF8, + new MediaTypeHeaderValue(MediaTypeNames.Application.Json)); + request.Method = HttpMethod.Post; + + var responseTask = httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken); + try { - using var response = await responseTask; - if (response.IsSuccessStatusCode) + await Task.WhenAny(timeout, lifetime, responseTask); + if (responseTask.IsCompleted) { - logger.LogDebug("Robust.Server responded to the shutdown command successfully. Waiting for exit..."); - await Task.WhenAny(timeout, lifetime); + using var response = await responseTask; + if (response.IsSuccessStatusCode) + { + logger.LogDebug("Robust.Server responded to the shutdown command successfully ({requestMs}ms). Waiting for exit...", stopwatch.ElapsedMilliseconds); + await Task.WhenAny(timeout, lifetime); + } } + + if (!lifetime.IsCompleted) + logger.LogWarning("Robust.Server graceful exit timed out!"); + } + catch (Exception ex) when (ex is not OperationCanceledException) + { + logger.LogDebug(ex, "Unable to send graceful exit request to Robust.Server watchdog API!"); } - if (!lifetime.IsCompleted) - logger.LogWarning("Robust.Server graceful exit timed out!"); - } - catch (HttpRequestException ex) - { - logger.LogDebug(ex, "Unable to send graceful exit request to Robust.Server watchdog API!"); + if (lifetime.IsCompleted) + { + logger.LogTrace("Robust.Server exited without termination"); + return; + } } - - if (lifetime.IsCompleted) + finally { - logger.LogTrace("Robust.Server exited without termination"); - return; + logger.LogTrace("Robust.Server graceful shutdown attempt took {totalMs}ms", stopwatch.ElapsedMilliseconds); } await base.StopServerProcess(logger, process, accessIdentifier, port, cancellationToken); From 679bc7d0cbbc2fea26ec82df4ea2e84f17c71c92 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 22:27:07 -0500 Subject: [PATCH 566/717] Switch back to dynamic live tests port allocation --- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 6edee102eab..60781753a29 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -147,9 +147,6 @@ static bool TerminateAllEngineServers() static ushort FreeTcpPort(params ushort[] usedPorts) { - var portList = new ushort[] { 42069, 42070, 42071, 42072, 42073, 42074 }; - return portList.First(x => !usedPorts.Contains(x)); - /* ushort result; var listeners = new List(); @@ -171,7 +168,7 @@ static ushort FreeTcpPort(params ushort[] usedPorts) result = (ushort)((IPEndPoint)l.LocalEndpoint).Port; } - while (usedPorts.Contains(result) || result < 10000); + while (usedPorts.Contains(result) || result < 20000); } finally { @@ -180,8 +177,9 @@ static ushort FreeTcpPort(params ushort[] usedPorts) l.Stop(); } } + + Console.WriteLine($"Allocated port: {result}"); return result; - */ } [ClassInitialize] From fda4b98ec36b506e66e20997c52009bf50a112a8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 22:53:26 -0500 Subject: [PATCH 567/717] Nullify `IRenameNotifyee` --- src/Tgstation.Server.Host/Components/IRenameNotifyee.cs | 2 -- src/Tgstation.Server.Host/Controllers/InstanceController.cs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/IRenameNotifyee.cs b/src/Tgstation.Server.Host/Components/IRenameNotifyee.cs index 5394921314b..be22158bd9d 100644 --- a/src/Tgstation.Server.Host/Components/IRenameNotifyee.cs +++ b/src/Tgstation.Server.Host/Components/IRenameNotifyee.cs @@ -1,8 +1,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index ddad25bca77..a0bab0791d0 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -444,7 +444,7 @@ bool CheckModified(Expression> expression, Insta await WithComponentInstanceNullable( async componentInstance => { - await componentInstance.InstanceRenamed(originalModel.Name, cancellationToken); + await componentInstance.InstanceRenamed(originalModel.Name!, cancellationToken); return null; }, originalModel); From 54e07bb68360e93d074eabbf365e6dfe67c57cd5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 22:54:29 -0500 Subject: [PATCH 568/717] Nullify `InstanceWrapper` --- src/Tgstation.Server.Host/Components/InstanceWrapper.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceWrapper.cs b/src/Tgstation.Server.Host/Components/InstanceWrapper.cs index 21861d17069..5c525d98698 100644 --- a/src/Tgstation.Server.Host/Components/InstanceWrapper.cs +++ b/src/Tgstation.Server.Host/Components/InstanceWrapper.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components { /// From b49f47c686ca0749709965974196a8f7706066d7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 22:54:40 -0500 Subject: [PATCH 569/717] Nullify `IComponentService` --- src/Tgstation.Server.Host/Components/IComponentService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/IComponentService.cs b/src/Tgstation.Server.Host/Components/IComponentService.cs index 6ef039f6548..b094e0a0929 100644 --- a/src/Tgstation.Server.Host/Components/IComponentService.cs +++ b/src/Tgstation.Server.Host/Components/IComponentService.cs @@ -1,7 +1,5 @@ using Microsoft.Extensions.Hosting; -#nullable disable - namespace Tgstation.Server.Host.Components { /// From 88788f91911e6d9821d79f318991dbc82279ac41 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 22:54:54 -0500 Subject: [PATCH 570/717] Nullify `IInstance` --- src/Tgstation.Server.Host/Components/IInstance.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/IInstance.cs b/src/Tgstation.Server.Host/Components/IInstance.cs index b7b75050538..9d8c34988e7 100644 --- a/src/Tgstation.Server.Host/Components/IInstance.cs +++ b/src/Tgstation.Server.Host/Components/IInstance.cs @@ -1,7 +1,5 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.Components { /// From ecf5ac1c8589be2cd8525d19809d813780fa0ec4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 22:55:11 -0500 Subject: [PATCH 571/717] Nullify `IInstanceCore` --- src/Tgstation.Server.Host/Components/IInstanceCore.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/IInstanceCore.cs b/src/Tgstation.Server.Host/Components/IInstanceCore.cs index 1fd3a29d454..78bce9e3f31 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceCore.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceCore.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Host.Components.StaticFiles; using Tgstation.Server.Host.Components.Watchdog; -#nullable disable - namespace Tgstation.Server.Host.Components { /// From 27f61eb693c95b64ae5015991904a50bf938e312 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 22:55:37 -0500 Subject: [PATCH 572/717] Nullify `IInstanceFactory` --- src/Tgstation.Server.Host/Components/IInstanceFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/IInstanceFactory.cs b/src/Tgstation.Server.Host/Components/IInstanceFactory.cs index 5728f7f632e..6258614b5f5 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceFactory.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.Components.Interop.Bridge; using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Components { /// From 468135464924fcf593ff787dd48cd37e3b89191c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 22:55:50 -0500 Subject: [PATCH 573/717] Nullify `IInstanceManager` --- src/Tgstation.Server.Host/Components/IInstanceManager.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/IInstanceManager.cs b/src/Tgstation.Server.Host/Components/IInstanceManager.cs index c9439c2bdbe..3174686efe8 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceManager.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Components.Interop.Bridge; -#nullable disable - namespace Tgstation.Server.Host.Components { /// From 13e4691782b38a2527fd42e18a7d6b354cffb2aa Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 22:57:19 -0500 Subject: [PATCH 574/717] Nullify `IInstanceOperations` --- src/Tgstation.Server.Host/Components/IInstanceOperations.cs | 2 -- .../Controllers/ComponentInterfacingController.cs | 5 +++-- src/Tgstation.Server.Host/Controllers/InstanceController.cs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/IInstanceOperations.cs b/src/Tgstation.Server.Host/Components/IInstanceOperations.cs index 8d81a1d69c3..3212d9d6dcf 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceOperations.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceOperations.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components { /// diff --git a/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs b/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs index 108390890fd..34988a58123 100644 --- a/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs +++ b/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs @@ -75,10 +75,11 @@ protected ComponentInterfacingController( if (AuthenticationContext.InstancePermissionSet == null) return Forbid(); - if (ValidateInstanceOnlineStatus(Instance!)) + var instance = Instance!; + if (ValidateInstanceOnlineStatus(instance)) await DatabaseContext.Save(cancellationToken); - using var instanceReferenceCheck = instanceManager.GetInstanceReference(Instance); + using var instanceReferenceCheck = instanceManager.GetInstanceReference(instance); if (instanceReferenceCheck == null) return Conflict(new ErrorMessageResponse(ErrorCode.InstanceOffline)); diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index a0bab0791d0..ded93134755 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -492,7 +492,7 @@ await WithComponentInstanceNullable( await jobManager.RegisterOperation( job, (core, databaseContextFactory, paramJob, progressHandler, ct) // core will be null here since the instance is offline - => InstanceOperations.MoveInstance(originalModel, originalModelPath, ct), + => InstanceOperations.MoveInstance(originalModel, originalModelPath!, ct), cancellationToken); api.MoveJob = job.ToApi(); } From 6fd47236459112103ccd12c99e9fd5b28922a9e8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 22:57:34 -0500 Subject: [PATCH 575/717] Nullify `IInstanceReference` --- src/Tgstation.Server.Host/Components/IInstanceReference.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/IInstanceReference.cs b/src/Tgstation.Server.Host/Components/IInstanceReference.cs index 14a63a76492..55f9379e80c 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceReference.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceReference.cs @@ -1,7 +1,5 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.Components { /// From 4cba11841084c7f90520f2c72e1d301193653bd2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:02:04 -0500 Subject: [PATCH 576/717] Nullify `Instance` --- .../Components/Instance.cs | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index e1421476d12..10be9b18a31 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -21,8 +21,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components { /// @@ -95,12 +93,12 @@ sealed class Instance : IInstance /// /// The auto update . /// - Task timerTask; + Task? timerTask; /// /// for . /// - CancellationTokenSource timerCts; + CancellationTokenSource? timerCts; /// /// Initializes a new instance of the class. @@ -185,7 +183,7 @@ public async Task StartAsync(CancellationToken cancellationToken) using (LogContext.PushProperty(SerilogContextHelper.InstanceIdContextProperty, metadata.Id)) { await Task.WhenAll( - SetAutoUpdateInterval(metadata.AutoUpdateInterval.Value).AsTask(), + SetAutoUpdateInterval(metadata.Require(x => x.AutoUpdateInterval)).AsTask(), Configuration.StartAsync(cancellationToken), EngineManager.StartAsync(cancellationToken), Chat.StartAsync(cancellationToken), @@ -223,7 +221,7 @@ public async ValueTask SetAutoUpdateInterval(uint newInterval) if (timerTask != null) { logger.LogTrace("Cancelling auto-update task"); - timerCts.Cancel(); + timerCts!.Cancel(); timerCts.Dispose(); toWait = timerTask; timerTask = null; @@ -317,18 +315,18 @@ await repo.FetchOrigin( cancellationToken); var hasDbChanges = false; - RevisionInformation currentRevInfo = null; - Models.Instance attachedInstance = null; - async ValueTask UpdateRevInfo(string currentHead, bool onOrigin, IEnumerable updatedTestMerges) + RevisionInformation? currentRevInfo = null; + Models.Instance? attachedInstance = null; + async ValueTask UpdateRevInfo(string currentHead, bool onOrigin, IEnumerable? updatedTestMerges) { if (currentRevInfo == null) { logger.LogTrace("Loading revision info for commit {sha}...", startSha[..7]); currentRevInfo = await databaseContext - .RevisionInformations + .RevisionInformations .AsQueryable() - .Where(x => x.CommitSha == startSha && x.Instance.Id == metadata.Id) - .Include(x => x.ActiveTestMerges) + .Where(x => x.CommitSha == startSha && x.InstanceId == metadata.Id) + .Include(x => x.ActiveTestMerges!) .ThenInclude(x => x.TestMerge) .FirstOrDefaultAsync(cancellationToken); } @@ -366,7 +364,7 @@ async ValueTask UpdateRevInfo(string currentHead, bool onOrigin, IEnumerable x.TestMerge); + var testMerges = updatedTestMerges ?? oldRevInfo!.ActiveTestMerges!.Select(x => x.TestMerge); var revInfoTestMerges = testMerges.Select( testMerge => new RevInfoTestMerge(testMerge, currentRevInfo)) .ToList(); @@ -381,10 +379,10 @@ async ValueTask UpdateRevInfo(string currentHead, bool onOrigin, IEnumerable x.CommitSha == currentHead && x.Instance.Id == metadata.Id) + .Where(x => x.CommitSha == currentHead && x.InstanceId == metadata.Id) .FirstOrDefaultAsync(cancellationToken); if (currentHead != startSha && currentRevInfo == default) @@ -452,7 +450,7 @@ await repo.ResetToOrigin( } // synch if necessary - if (repositorySettings.AutoUpdatesSynchronize.Value && startSha != repo.Head && (shouldSyncTracked || repositorySettings.PushTestMergeCommits.Value)) + if (repositorySettings.AutoUpdatesSynchronize!.Value && startSha != repo.Head && (shouldSyncTracked || repositorySettings.PushTestMergeCommits!.Value)) { var pushedOrigin = await repo.Sychronize( NextProgressReporter("Synchronize"), @@ -464,7 +462,7 @@ await repo.ResetToOrigin( true, cancellationToken); var currentHead = repo.Head; - if (currentHead != currentRevInfo.CommitSha) + if (currentHead != currentRevInfo!.CommitSha) await UpdateRevInfo(currentHead, pushedOrigin, null); } From 44d21478f10981b455c4b4ebfc0d2ff50ce7c448 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:02:42 -0500 Subject: [PATCH 577/717] Nullify `InstanceFactory` --- src/Tgstation.Server.Host/Components/InstanceFactory.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index a9f5878c417..3f9cf25dc4e 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -25,8 +25,6 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components { /// @@ -332,7 +330,7 @@ public async ValueTask CreateInstance(IBridgeRegistrar bridgeRegistra eventConsumer.SetWatchdog(watchdog); commandFactory.SetWatchdog(watchdog); - Instance instance = null; + Instance? instance = null; var dreamMaker = new DreamMaker( engineManager, gameIoManager, @@ -406,6 +404,6 @@ public Task StartAsync(CancellationToken cancellationToken) /// /// The . /// The for the . - IIOManager CreateInstanceIOManager(Models.Instance metadata) => new ResolvingIOManager(ioManager, metadata.Path); + IIOManager CreateInstanceIOManager(Models.Instance metadata) => new ResolvingIOManager(ioManager, metadata.Path!); } } From 87d3b916664bc8e73b79d1ec5dc7fe8e92ec8cd9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:03:44 -0500 Subject: [PATCH 578/717] Cleanup messages in `InstanceFactory` --- src/Tgstation.Server.Host/Components/InstanceFactory.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index 3f9cf25dc4e..7f621333e83 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -150,7 +150,7 @@ sealed class InstanceFactory : IInstanceFactory /// /// The instance's . /// The for the instance's "Game" directory. - static IIOManager CreateGameIOManager(IIOManager instanceIOManager) => new ResolvingIOManager(instanceIOManager, "Game"); + static ResolvingIOManager CreateGameIOManager(IIOManager instanceIOManager) => new(instanceIOManager, "Game"); #pragma warning disable CA1502 // TODO: Decomplexify /// @@ -404,6 +404,6 @@ public Task StartAsync(CancellationToken cancellationToken) /// /// The . /// The for the . - IIOManager CreateInstanceIOManager(Models.Instance metadata) => new ResolvingIOManager(ioManager, metadata.Path!); + ResolvingIOManager CreateInstanceIOManager(Models.Instance metadata) => new(ioManager, metadata.Path!); } } From 476e903bb05c18f68274826d3ec6410328811eb0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:04:17 -0500 Subject: [PATCH 579/717] Cleanup messages in tests --- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 12 ++++++------ tests/Tgstation.Server.Tests/TestVersions.cs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 60781753a29..96ee8ba640e 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -54,12 +54,12 @@ public sealed class TestLiveServer { public static readonly Version TestUpdateVersion = new(5, 11, 0); - static readonly Lazy odDMPort = new Lazy(() => FreeTcpPort()); - static readonly Lazy odDDPort = new Lazy(() => FreeTcpPort(odDMPort.Value)); - static readonly Lazy compatDMPort = new Lazy(() => FreeTcpPort(odDDPort.Value, odDMPort.Value)); - static readonly Lazy compatDDPort = new Lazy(() => FreeTcpPort(odDDPort.Value, odDMPort.Value, compatDMPort.Value)); - static readonly Lazy mainDDPort = new Lazy(() => FreeTcpPort(odDDPort.Value, odDMPort.Value, compatDMPort.Value, compatDDPort.Value)); - static readonly Lazy mainDMPort = new Lazy(() => FreeTcpPort(odDDPort.Value, odDMPort.Value, compatDMPort.Value, compatDDPort.Value, mainDDPort.Value)); + static readonly Lazy odDMPort = new(() => FreeTcpPort()); + static readonly Lazy odDDPort = new(() => FreeTcpPort(odDMPort.Value)); + static readonly Lazy compatDMPort = new(() => FreeTcpPort(odDDPort.Value, odDMPort.Value)); + static readonly Lazy compatDDPort = new(() => FreeTcpPort(odDDPort.Value, odDMPort.Value, compatDMPort.Value)); + static readonly Lazy mainDDPort = new(() => FreeTcpPort(odDDPort.Value, odDMPort.Value, compatDMPort.Value, compatDDPort.Value)); + static readonly Lazy mainDMPort = new(() => FreeTcpPort(odDDPort.Value, odDMPort.Value, compatDMPort.Value, compatDDPort.Value, mainDDPort.Value)); readonly ServerClientFactory clientFactory = new (new ProductHeaderValue(Assembly.GetExecutingAssembly().GetName().Name, Assembly.GetExecutingAssembly().GetName().Version.ToString())); diff --git a/tests/Tgstation.Server.Tests/TestVersions.cs b/tests/Tgstation.Server.Tests/TestVersions.cs index 01fdf2d0ec1..7b52b79773a 100644 --- a/tests/Tgstation.Server.Tests/TestVersions.cs +++ b/tests/Tgstation.Server.Tests/TestVersions.cs @@ -494,7 +494,7 @@ static async Task TestMapThreadsVersion( var shouldSupportMapThreads = engineVersion.Version >= MapThreadsVersion(); - await File.WriteAllBytesAsync("fake.dmb", Array.Empty(), CancellationToken.None); + await File.WriteAllBytesAsync("fake.dmb", [], CancellationToken.None); try { From 5bffb97cdb0eca9db40dbf46fce98735aca912c3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:11:33 -0500 Subject: [PATCH 580/717] Nullify `InstanceManager` --- .../Components/IInstanceCoreProvider.cs | 2 +- .../Components/IInstanceManager.cs | 2 +- .../Components/InstanceManager.cs | 57 +++++++++++-------- .../ComponentInterfacingController.cs | 2 +- src/Tgstation.Server.Host/Jobs/JobService.cs | 4 +- 5 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/IInstanceCoreProvider.cs b/src/Tgstation.Server.Host/Components/IInstanceCoreProvider.cs index 7e6b0b8dc52..ab1db54e915 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceCoreProvider.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceCoreProvider.cs @@ -10,6 +10,6 @@ public interface IInstanceCoreProvider /// /// The to get the for. /// The if it is online, otherwise. - IInstanceCore GetInstance(Models.Instance instance); + IInstanceCore? GetInstance(Models.Instance instance); } } diff --git a/src/Tgstation.Server.Host/Components/IInstanceManager.cs b/src/Tgstation.Server.Host/Components/IInstanceManager.cs index 3174686efe8..516b2a8f302 100644 --- a/src/Tgstation.Server.Host/Components/IInstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/IInstanceManager.cs @@ -19,6 +19,6 @@ public interface IInstanceManager : IInstanceOperations, IBridgeDispatcher /// /// The of the desired . /// The associated with the given if it is online, otherwise. - IInstanceReference GetInstanceReference(Api.Models.Instance metadata); + IInstanceReference? GetInstanceReference(Api.Models.Instance metadata); } } diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index 50da066c525..eeadde0c30a 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -21,13 +21,12 @@ using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; +using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Swarm; using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components { /// @@ -117,7 +116,7 @@ sealed class InstanceManager : readonly Dictionary bridgeHandlers; /// - /// used to guard calls to and . + /// used to guard calls to and . /// readonly SemaphoreSlim instanceStateChangeSemaphore; @@ -149,12 +148,12 @@ sealed class InstanceManager : /// /// The original of . /// - readonly string originalConsoleTitle; + readonly string? originalConsoleTitle; /// /// The returned by . /// - Task startupTask; + Task? startupTask; /// /// If the has been 'd. @@ -243,13 +242,13 @@ public async ValueTask DisposeAsync() } /// - public IInstanceReference GetInstanceReference(Api.Models.Instance metadata) + public IInstanceReference? GetInstanceReference(Api.Models.Instance metadata) { ArgumentNullException.ThrowIfNull(metadata); lock (instances) { - if (!instances.TryGetValue(metadata.Id.Value, out var instance)) + if (!instances.TryGetValue(metadata.Require(x => x.Id), out var instance)) return null; return instance.AddReference(); @@ -265,7 +264,7 @@ public async ValueTask MoveInstance(Models.Instance instance, string oldPath, Ca using var instanceReferenceCheck = GetInstanceReference(instance); if (instanceReferenceCheck != null) throw new InvalidOperationException("Cannot move an online instance!"); - var newPath = instance.Path; + var newPath = instance.Path!; try { await ioManager.MoveDirectory(oldPath, newPath, cancellationToken); @@ -328,22 +327,23 @@ await ioManager.WriteAllBytes( } /// - public async ValueTask OfflineInstance(Models.Instance metadata, Models.User user, CancellationToken cancellationToken) + public async ValueTask OfflineInstance(Models.Instance metadata, User user, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(metadata); using (await SemaphoreSlimContext.Lock(instanceStateChangeSemaphore, cancellationToken)) { - ReferenceCountingContainer container; + ReferenceCountingContainer? container; + var instanceId = metadata.Require(x => x.Id); lock (instances) { - if (!instances.TryGetValue(metadata.Id.Value, out container)) + if (!instances.TryGetValue(instanceId, out container)) { logger.LogDebug("Not offlining removed instance {instanceId}", metadata.Id); return; } - instances.Remove(metadata.Id.Value); + instances.Remove(instanceId); } logger.LogInformation("Offlining instance ID {instanceId}", metadata.Id); @@ -353,15 +353,15 @@ public async ValueTask OfflineInstance(Models.Instance metadata, Models.User use await container.OnZeroReferences.WaitAsync(cancellationToken); // we are the one responsible for cancelling his jobs - ValueTask groupedTask = default; + ValueTask groupedTask = default; await databaseContextFactory.UseContext( async db => { var jobs = await db .Jobs .AsQueryable() - .Where(x => x.Instance.Id == metadata.Id && !x.StoppedAt.HasValue) - .Select(x => new Models.Job(x.Id.Value)) + .Where(x => x.Instance!.Id == metadata.Id && !x.StoppedAt.HasValue) + .Select(x => new Job(x.Id!.Value)) .ToListAsync(cancellationToken); groupedTask = ValueTaskExtensions.WhenAll( @@ -375,7 +375,7 @@ await databaseContextFactory.UseContext( { // not too late to change your mind lock (instances) - instances.Add(metadata.Id.Value, container); + instances.Add(instanceId, container); throw; } @@ -397,9 +397,10 @@ public async ValueTask OnlineInstance(Models.Instance metadata, CancellationToke { ArgumentNullException.ThrowIfNull(metadata); + var instanceId = metadata.Require(x => x.Id); using var lockContext = await SemaphoreSlimContext.Lock(instanceStateChangeSemaphore, cancellationToken); lock (instances) - if (instances.ContainsKey(metadata.Id.Value)) + if (instances.ContainsKey(instanceId)) { logger.LogDebug("Aborting instance creation due to it seemingly already being online"); return; @@ -415,7 +416,7 @@ public async ValueTask OnlineInstance(Models.Instance metadata, CancellationToke { lock (instances) instances.Add( - metadata.Id.Value, + instanceId, new ReferenceCountingContainer(instance)); } catch (Exception ex) @@ -457,6 +458,12 @@ public async Task StopAsync(CancellationToken cancellationToken) using (cancellationToken.Register(shutdownCancellationTokenSource.Cancel)) try { + if (startupTask == null) + { + logger.LogWarning("InstanceManager was never started!"); + return; + } + logger.LogDebug("Stopping instance manager..."); if (!startupTask.IsCompleted) @@ -499,11 +506,11 @@ async ValueTask OfflineInstanceImmediate(IInstance instance, CancellationToken c } /// - public async ValueTask ProcessBridgeRequest(BridgeParameters parameters, CancellationToken cancellationToken) + public async ValueTask ProcessBridgeRequest(BridgeParameters parameters, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(parameters); - IBridgeHandler bridgeHandler = null; + IBridgeHandler? bridgeHandler = null; for (var i = 0; bridgeHandler == null && i < 30; ++i) { // There's a miniscule time period where we could potentially receive a bridge request and not have the registration ready when we launch DD @@ -550,11 +557,11 @@ public IBridgeRegistration RegisterHandler(IBridgeHandler bridgeHandler) } /// - public IInstanceCore GetInstance(Models.Instance metadata) + public IInstanceCore? GetInstance(Models.Instance metadata) { lock (instances) { - instances.TryGetValue(metadata.Id.Value, out var container); + instances.TryGetValue(metadata.Require(x => x.Id), out var container); return container?.Instance; } } @@ -578,13 +585,13 @@ async Task Initialize(CancellationToken cancellationToken) await InitializeSwarm(cancellationToken); - List dbInstances = null; + List? dbInstances = null; async ValueTask EnumerateInstances(IDatabaseContext databaseContext) => dbInstances = await databaseContext .Instances .AsQueryable() - .Where(x => x.Online.Value && x.SwarmIdentifer == swarmConfiguration.Identifier) + .Where(x => x.Online!.Value && x.SwarmIdentifer == swarmConfiguration.Identifier) .Include(x => x.RepositorySettings) .Include(x => x.ChatSettings) .ThenInclude(x => x.Channels) @@ -598,7 +605,7 @@ async ValueTask EnumerateInstances(IDatabaseContext databaseContext) await Task.WhenAll(instanceEnumeration.AsTask(), factoryStartup, jobManagerStartup); - var instanceOnliningTasks = dbInstances.Select( + var instanceOnliningTasks = dbInstances!.Select( async metadata => { try diff --git a/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs b/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs index 34988a58123..f04e620d06a 100644 --- a/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs +++ b/src/Tgstation.Server.Host/Controllers/ComponentInterfacingController.cs @@ -129,7 +129,7 @@ protected bool ValidateInstanceOnlineStatus(Api.Models.Instance metadata) instance ??= Instance ?? throw new InvalidOperationException("ComponentInterfacingController has no Instance!"); using var instanceReference = instanceManager.GetInstanceReference(instance); - using (LogContext.PushProperty(SerilogContextHelper.InstanceReferenceContextProperty, instanceReference.Uid)) + using (LogContext.PushProperty(SerilogContextHelper.InstanceReferenceContextProperty, instanceReference?.Uid)) { if (instanceReference == null) return Conflict(new ErrorMessageResponse(ErrorCode.InstanceOffline)); diff --git a/src/Tgstation.Server.Host/Jobs/JobService.cs b/src/Tgstation.Server.Host/Jobs/JobService.cs index ea2782a8218..8db21d3068c 100644 --- a/src/Tgstation.Server.Host/Jobs/JobService.cs +++ b/src/Tgstation.Server.Host/Jobs/JobService.cs @@ -460,8 +460,10 @@ void UpdateProgress(string? stage, double? progress) QueueHubUpdate(job.ToApi(), false); logger.LogTrace("Starting job..."); + var instanceCore = instanceCoreProvider.GetInstance(job.Instance!) + ?? throw new JobException("Could not retrieve instance core for job!"); await operation( - instanceCoreProvider.GetInstance(job.Instance!), + instanceCore, databaseContextFactory, job, new JobProgressReporter( From 9bab2f5d5ad74b12e2657805a3fcff55f6c50f9b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:16:15 -0500 Subject: [PATCH 581/717] Nullify `IConfiguration` --- .../Components/StaticFiles/IConfiguration.cs | 14 ++++++-------- .../Controllers/ConfigurationController.cs | 5 ++++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs index 63b940d6469..db32cc1c2b7 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs @@ -8,8 +8,6 @@ using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.Security; -#nullable disable - namespace Tgstation.Server.Host.Components.StaticFiles { /// @@ -24,7 +22,7 @@ public interface IConfiguration : IComponentService, IEventConsumer, IDisposable /// Path to the destination folder. /// The for the operation. /// A resulting in the if any. - ValueTask CopyDMFilesTo(string dmeFile, string destination, CancellationToken cancellationToken); + ValueTask CopyDMFilesTo(string dmeFile, string destination, CancellationToken cancellationToken); /// /// Symlinks all directories in the GameData directory to . @@ -41,7 +39,7 @@ public interface IConfiguration : IComponentService, IEventConsumer, IDisposable /// The for the operation. If , the operation will be performed as the user of the . /// The for the operation. /// A resulting in an of the s for the items in the directory. and will both be . will be returned if the operation failed due to access contention. - ValueTask> ListDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken); + ValueTask> ListDirectory(string? configurationRelativePath, ISystemIdentity? systemIdentity, CancellationToken cancellationToken); /// /// Reads a given . @@ -50,7 +48,7 @@ public interface IConfiguration : IComponentService, IEventConsumer, IDisposable /// The for the operation. If , the operation will be performed as the user of the . /// The for the operation. /// A resulting in the of the file. will be returned if the operation failed due to access contention. - ValueTask Read(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken); + ValueTask Read(string configurationRelativePath, ISystemIdentity? systemIdentity, CancellationToken cancellationToken); /// /// Create an empty directory at . @@ -59,7 +57,7 @@ public interface IConfiguration : IComponentService, IEventConsumer, IDisposable /// The for the operation. If , the operation will be performed as the user of the . /// The for the operation. Usage may result in partial writes. /// A resulting in if the directory already existed, otherwise. will be returned if the operation failed due to access contention. - ValueTask CreateDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken); + ValueTask CreateDirectory(string configurationRelativePath, ISystemIdentity? systemIdentity, CancellationToken cancellationToken); /// /// Attempt to delete an empty directory at . @@ -68,7 +66,7 @@ public interface IConfiguration : IComponentService, IEventConsumer, IDisposable /// The for the operation. If , the operation will be performed as the user of the . /// The for the operation. /// A resulting in if the directory was empty and deleted, otherwise. will be returned if the operation failed due to access contention. - ValueTask DeleteDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken); + ValueTask DeleteDirectory(string configurationRelativePath, ISystemIdentity? systemIdentity, CancellationToken cancellationToken); /// /// Writes to a given . @@ -78,6 +76,6 @@ public interface IConfiguration : IComponentService, IEventConsumer, IDisposable /// The hash any existing file must match in order for the write to succeed. /// The for the operation. Usage may result in partial writes. /// A resulting in the updated and associated writing . will be returned if the operation failed due to access contention. - ValueTask Write(string configurationRelativePath, ISystemIdentity systemIdentity, string previousHash, CancellationToken cancellationToken); + ValueTask Write(string configurationRelativePath, ISystemIdentity? systemIdentity, string? previousHash, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs b/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs index 1df1fbc9079..8232be095c0 100644 --- a/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs +++ b/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs @@ -84,7 +84,7 @@ public async ValueTask Update([FromBody] ConfigurationFileRequest var newFile = await instance .Configuration .Write( - model.Path, + model.Path!, systemIdentity, model.LastReadHash, cancellationToken); @@ -240,6 +240,9 @@ public async ValueTask CreateDirectory([FromBody] ConfigurationFi { ArgumentNullException.ThrowIfNull(model); + if (model.Path == null) + return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)); + if (ForbidDueToModeConflicts(model.Path, out var systemIdentity)) return Forbid(); From 921b2b44fc67ca2407277a1c47a2dd5abbed7ff6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:20:20 -0500 Subject: [PATCH 582/717] Nullify `Configuration` --- .../Components/StaticFiles/Configuration.cs | 41 +++++++++++-------- .../Components/StaticFiles/IConfiguration.cs | 2 +- .../StaticFiles/ServerSideModifications.cs | 6 +-- .../IO/DefaultIOManager.cs | 2 +- src/Tgstation.Server.Host/IO/IIOManager.cs | 2 +- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs index 3644f20991e..b2e12d19473 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs @@ -23,8 +23,6 @@ using Tgstation.Server.Host.Transfer; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.StaticFiles { /// @@ -80,7 +78,7 @@ sealed class Configuration : IConfiguration eventType => new KeyValuePair>( eventType, typeof(EventType) - .GetField(eventType.ToString()) + .GetField(eventType.ToString())! .GetCustomAttributes(false) .OfType() .First() @@ -201,7 +199,7 @@ public void Dispose() } /// - public async ValueTask CopyDMFilesTo(string dmeFile, string destination, CancellationToken cancellationToken) + public async ValueTask CopyDMFilesTo(string dmeFile, string destination, CancellationToken cancellationToken) { using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken)) { @@ -234,12 +232,19 @@ public async ValueTask CopyDMFilesTo(string dmeFile, st static string IncludeLine(string filePath) => String.Format(CultureInfo.InvariantCulture, "#include \"{0}\"", filePath); - return new ServerSideModifications(headFileExistsTask.Result ? IncludeLine(CodeModificationsHeadFile) : null, tailFileExistsTask.Result ? IncludeLine(CodeModificationsTailFile) : null, false); + return new ServerSideModifications( + headFileExistsTask.Result + ? IncludeLine(CodeModificationsHeadFile) + : null, + tailFileExistsTask.Result + ? IncludeLine(CodeModificationsTailFile) + : null, + false); } } /// - public async ValueTask> ListDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken) + public async ValueTask?> ListDirectory(string? configurationRelativePath, ISystemIdentity? systemIdentity, CancellationToken cancellationToken) { await EnsureDirectories(cancellationToken); var path = ValidateConfigRelativePath(configurationRelativePath); @@ -286,12 +291,12 @@ void ListImpl() } /// - public async ValueTask Read(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken) + public async ValueTask Read(string configurationRelativePath, ISystemIdentity? systemIdentity, CancellationToken cancellationToken) { await EnsureDirectories(cancellationToken); var path = ValidateConfigRelativePath(configurationRelativePath); - ConfigurationFileResponse result = null; + ConfigurationFileResponse? result = null; void ReadImpl() { @@ -321,7 +326,7 @@ string GetFileSha() }, async cancellationToken => { - FileStream result = null; + FileStream? result = null; void GetFileStream() { result = ioManager.GetFileStream(path, false); @@ -332,7 +337,7 @@ void GetFileStream() else await systemIdentity.RunImpersonated(GetFileStream, cancellationToken); - return result; + return result!; }, path, false)); @@ -453,12 +458,12 @@ await ValueTaskExtensions.WhenAll(entries.Select(async file = } /// - public async ValueTask Write(string configurationRelativePath, ISystemIdentity systemIdentity, string previousHash, CancellationToken cancellationToken) + public async ValueTask Write(string configurationRelativePath, ISystemIdentity? systemIdentity, string? previousHash, CancellationToken cancellationToken) { await EnsureDirectories(cancellationToken); var path = ValidateConfigRelativePath(configurationRelativePath); - ConfigurationFileResponse result = null; + ConfigurationFileResponse? result = null; void WriteImpl() { @@ -563,7 +568,7 @@ void WriteCallback() } /// - public async ValueTask CreateDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken) + public async ValueTask CreateDirectory(string configurationRelativePath, ISystemIdentity? systemIdentity, CancellationToken cancellationToken) { await EnsureDirectories(cancellationToken); var path = ValidateConfigRelativePath(configurationRelativePath); @@ -585,7 +590,7 @@ void WriteCallback() await systemIdentity.RunImpersonated(DoCreate, cancellationToken); } - return result.Value; + return result!.Value; } /// @@ -659,7 +664,7 @@ public async ValueTask HandleEvent(EventType eventType, IEnumerable para } /// - public async ValueTask DeleteDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken) + public async ValueTask DeleteDirectory(string configurationRelativePath, ISystemIdentity? systemIdentity, CancellationToken cancellationToken) { await EnsureDirectories(cancellationToken); var path = ValidateConfigRelativePath(configurationRelativePath); @@ -737,16 +742,16 @@ async Task ValidateCodeModsFolder() /// /// A relative path in the instance's configuration directory. /// The full on-disk path of . - string ValidateConfigRelativePath(string configurationRelativePath) + string ValidateConfigRelativePath(string? configurationRelativePath) { var nullOrEmptyCheck = String.IsNullOrEmpty(configurationRelativePath); if (nullOrEmptyCheck) configurationRelativePath = DefaultIOManager.CurrentDirectory; - if (configurationRelativePath[0] == Path.DirectorySeparatorChar || configurationRelativePath[0] == Path.AltDirectorySeparatorChar) + if (configurationRelativePath![0] == Path.DirectorySeparatorChar || configurationRelativePath[0] == Path.AltDirectorySeparatorChar) configurationRelativePath = DefaultIOManager.CurrentDirectory + configurationRelativePath; var resolved = ioManager.ResolvePath(configurationRelativePath); var local = !nullOrEmptyCheck ? ioManager.ResolvePath() : null; - if (!nullOrEmptyCheck && resolved.Length < local.Length) // .. fuccbois + if (!nullOrEmptyCheck && resolved.Length < local!.Length) // .. fuccbois throw new InvalidOperationException("Attempted to access file outside of configuration manager!"); return resolved; } diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs index db32cc1c2b7..d156df54cb2 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/IConfiguration.cs @@ -39,7 +39,7 @@ public interface IConfiguration : IComponentService, IEventConsumer, IDisposable /// The for the operation. If , the operation will be performed as the user of the . /// The for the operation. /// A resulting in an of the s for the items in the directory. and will both be . will be returned if the operation failed due to access contention. - ValueTask> ListDirectory(string? configurationRelativePath, ISystemIdentity? systemIdentity, CancellationToken cancellationToken); + ValueTask?> ListDirectory(string? configurationRelativePath, ISystemIdentity? systemIdentity, CancellationToken cancellationToken); /// /// Reads a given . diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/ServerSideModifications.cs b/src/Tgstation.Server.Host/Components/StaticFiles/ServerSideModifications.cs index 6b7e358f0b5..e28920a06ed 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/ServerSideModifications.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/ServerSideModifications.cs @@ -13,12 +13,12 @@ public sealed class ServerSideModifications /// /// The #include line which should be added to the beginning of the .dme if any. /// - public string HeadIncludeLine { get; } + public string? HeadIncludeLine { get; } /// /// The #include line which should be added to the end of the .dme if any. /// - public string TailIncludeLine { get; } + public string? TailIncludeLine { get; } /// /// Initializes a new instance of the class. @@ -26,7 +26,7 @@ public sealed class ServerSideModifications /// The value of . /// The value of . /// The value of . - public ServerSideModifications(string headIncludeLine, string tailIncludeLine, bool totalDmeOverwrite) + public ServerSideModifications(string? headIncludeLine, string? tailIncludeLine, bool totalDmeOverwrite) { HeadIncludeLine = headIncludeLine; TailIncludeLine = tailIncludeLine; diff --git a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs index 89231a6a49d..1126bafc7d2 100644 --- a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs +++ b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs @@ -69,7 +69,7 @@ static void NormalizeAndDelete(DirectoryInfo dir, CancellationToken cancellation /// public async ValueTask CopyDirectory( - IEnumerable ignore, + IEnumerable? ignore, Func? postCopyCallback, string src, string dest, diff --git a/src/Tgstation.Server.Host/IO/IIOManager.cs b/src/Tgstation.Server.Host/IO/IIOManager.cs index ed4a90fb526..d88ec3ec176 100644 --- a/src/Tgstation.Server.Host/IO/IIOManager.cs +++ b/src/Tgstation.Server.Host/IO/IIOManager.cs @@ -56,7 +56,7 @@ public interface IIOManager /// The for the operation. /// A representing the running operation. ValueTask CopyDirectory( - IEnumerable ignore, + IEnumerable? ignore, Func? postCopyCallback, string src, string dest, From 5222c4ed1eb6a2df98e889a2401037fc050b94aa Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:21:14 -0500 Subject: [PATCH 583/717] Simplify a collection initialization expression --- src/Tgstation.Server.Host/IO/DefaultIOManager.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs index 1126bafc7d2..cdae64ce445 100644 --- a/src/Tgstation.Server.Host/IO/DefaultIOManager.cs +++ b/src/Tgstation.Server.Host/IO/DefaultIOManager.cs @@ -303,11 +303,10 @@ public Task ZipToDirectory(string path, Stream zipFile, CancellationToken cancel /// public bool PathContainsParentAccess(string path) => path ?.Split( - new[] - { + [ Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar, - }) + ]) .Any(x => x == "..") ?? throw new ArgumentNullException(nameof(path)); From 1e3868d72d6fb8f234501753aa4fd248931bffdb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:21:26 -0500 Subject: [PATCH 584/717] Nullify `EventConsumer` --- src/Tgstation.Server.Host/Components/Events/EventConsumer.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs index ae805853fb7..8cc073ccda2 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Host.Components.StaticFiles; using Tgstation.Server.Host.Components.Watchdog; -#nullable disable - namespace Tgstation.Server.Host.Components.Events { /// @@ -21,7 +19,7 @@ sealed class EventConsumer : IEventConsumer /// /// The for the . /// - IWatchdog watchdog; + IWatchdog? watchdog; /// /// Initializes a new instance of the class. From 92f53a75c0c904f7fa476dc371e505964535fffc Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:21:38 -0500 Subject: [PATCH 585/717] Nullify `EventScriptAttribute` --- .../Components/Events/EventScriptAttribute.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs b/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs index fafcd825623..ba93d34cf95 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventScriptAttribute.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -#nullable disable - namespace Tgstation.Server.Host.Components.Events { /// From 0c16676596b7853c538c7b39d505a27598c4f672 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:21:52 -0500 Subject: [PATCH 586/717] Nullify `IEventConsumer` --- src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs index 4c2a7be5bd3..7fddbb8950f 100644 --- a/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs +++ b/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Components.Events { /// From b3e0a891dfbe4e336fa444267ddcfa8a87f0eb97 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:22:03 -0500 Subject: [PATCH 587/717] Nullify `NoopEventConsumer` --- .../Components/Events/NoopEventConsumer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs index 531018f7b55..a8b07e4d7e0 100644 --- a/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs +++ b/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Components.Events { /// From f819766a5b503a21b6c90edf4f93db1ae73b8788 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:34:29 -0500 Subject: [PATCH 588/717] Nullify `ChatUser` Clean up nullification of `ChannelRepresentation` as well --- .../Components/Chat/ChannelRepresentation.cs | 6 ++-- .../Components/Chat/ChatManager.cs | 2 +- .../Components/Chat/ChatUser.cs | 31 ++++++++++++++----- .../Chat/Providers/DiscordProvider.cs | 12 +++---- .../Components/Chat/Providers/IrcProvider.cs | 12 +++---- .../Live/DummyChatProvider.cs | 12 +++---- .../Live/Instance/WatchdogTest.cs | 14 +++------ 7 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChannelRepresentation.cs b/src/Tgstation.Server.Host/Components/Chat/ChannelRepresentation.cs index b7bed776d65..b1d4aa3ad20 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChannelRepresentation.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChannelRepresentation.cs @@ -14,7 +14,7 @@ public sealed class ChannelRepresentation /// /// Backing field for . Represented as a to avoid BYOND percision loss. /// - public string Id { get; set; } + public string Id { get; private set; } /// /// The channel Id. @@ -45,7 +45,7 @@ public ulong RealId /// /// If this is a 1-to-1 chat channel. /// - public bool IsPrivateChannel { get; set; } + public bool IsPrivateChannel { get; init; } /// /// For user use. @@ -55,7 +55,7 @@ public ulong RealId /// /// If this channel supports embeds. /// - public bool EmbedsSupported { get; set; } + public bool EmbedsSupported { get; init; } /// /// Initializes a new instance of the class. diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index 505a94d8179..36812e77434 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -798,7 +798,7 @@ ValueTask TextReply(string reply) => SendMessage( var mappingChannelRepresentation = mappedChannel.Value.Value.Channel; - message.User.Channel.Id = mappingChannelRepresentation.Id; + message.User.Channel.RealId = mappingChannelRepresentation.RealId; message.User.Channel.Tag = mappingChannelRepresentation.Tag; message.User.Channel.IsAdminChannel = mappingChannelRepresentation.IsAdminChannel; } diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatUser.cs b/src/Tgstation.Server.Host/Components/Chat/ChatUser.cs index 9660bc6c83b..69757279b07 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatUser.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatUser.cs @@ -3,8 +3,6 @@ using Newtonsoft.Json; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat { /// @@ -15,7 +13,7 @@ public sealed class ChatUser /// /// Backing field for . Represented as a to avoid BYOND percision loss. /// - public string Id { get; set; } + public string Id { get; private set; } /// /// The internal user id. @@ -23,23 +21,40 @@ public sealed class ChatUser [JsonIgnore] public ulong RealId { - get => UInt64.Parse(Id, CultureInfo.InvariantCulture); - set => Id = value.ToString(CultureInfo.InvariantCulture); + get => UInt64.Parse(Id!, CultureInfo.InvariantCulture); + private set => Id = value.ToString(CultureInfo.InvariantCulture); } /// /// The friendly name of the user. /// - public string FriendlyName { get; set; } + public string FriendlyName { get; } /// /// The text to mention the user. /// - public string Mention { get; set; } + public string Mention { get; } /// /// The the user spoke from. /// - public ChannelRepresentation Channel { get; set; } + public ChannelRepresentation Channel { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + /// The value of . + /// The value of . + /// The value of . + public ChatUser(ChannelRepresentation channel, string friendlyName, string mention, ulong realId) + { + Channel = channel ?? throw new ArgumentNullException(nameof(channel)); + FriendlyName = friendlyName ?? throw new ArgumentNullException(nameof(friendlyName)); + Mention = mention ?? throw new ArgumentNullException(nameof(mention)); + + Id = null!; + RealId = realId; + } } } diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 958aa54b261..6d06322dfc8 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -531,10 +531,8 @@ public async Task RespondAsync(IMessageCreate messageCreateEvent, Cancel } var result = new DiscordMessage( - new ChatUser - { - RealId = messageCreateEvent.Author.ID.Value, - Channel = new ChannelRepresentation( + new ChatUser( + new ChannelRepresentation( pm ? messageCreateEvent.Author.Username : guildName, channelResponse.Entity.Name.Value!, messageCreateEvent.ChannelID.Value) @@ -544,9 +542,9 @@ public async Task RespondAsync(IMessageCreate messageCreateEvent, Cancel // isAdmin and Tag populated by manager }, - FriendlyName = messageCreateEvent.Author.Username, - Mention = NormalizeMentions($"<@{messageCreateEvent.Author.ID}>"), - }, + messageCreateEvent.Author.Username, + NormalizeMentions($"<@{messageCreateEvent.Author.ID}>"), + messageCreateEvent.Author.ID.Value), content, messageReference); diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index 5207cc380d8..f8dfec41975 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -530,19 +530,17 @@ ulong MapAndGetChannelId(Dictionary dicToCheck) var channelFriendlyName = isPrivate ? String.Format(CultureInfo.InvariantCulture, "PM: {0}", channelName) : channelName; var message = new Message( - new ChatUser - { - Channel = new ChannelRepresentation(address, channelFriendlyName, channelId) + new ChatUser( + new ChannelRepresentation(address, channelFriendlyName, channelId) { IsPrivateChannel = isPrivate, EmbedsSupported = false, // isAdmin and Tag populated by manager }, - FriendlyName = username, - RealId = userId, - Mention = username, - }, + username, + username, + userId), e.Data.Message); EnqueueMessage(message); diff --git a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs index 8997c228415..debbf913b82 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs @@ -279,13 +279,11 @@ async Task RandomMessageLoop(CancellationToken cancellationToken) channel = enumerator[index].Value; } - var sender = new ChatUser - { - Channel = CloneChannel(channel), - FriendlyName = username, - RealId = i + 50000, - Mention = $"@{username}", - }; + var sender = new ChatUser( + CloneChannel(channel), + username, + $"@{username}", + i + 50000); var dice = random.Next(0, 100); string content; diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 4b08e3ae1fb..24e1dca4719 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -1024,20 +1024,16 @@ async Task WhiteBoxChatCommandTest(CancellationToken cancellationToken) var startTime = DateTimeOffset.UtcNow - TimeSpan.FromSeconds(5); using (var instanceReference = instanceManager.GetInstanceReference(instanceClient.Metadata)) { - var mockChatUser = new ChatUser - { - Channel = new ChannelRepresentation("test_connection", "Test Connection", 0) + var mockChatUser = new ChatUser( + new ChannelRepresentation("test_connection", "Test Connection", 42) { IsAdminChannel = true, EmbedsSupported = true, - Id = "test_channel_id", IsPrivateChannel = false, }, - FriendlyName = "Test Sender", - Id = "test_user_id", - Mention = "test_user_mention", - RealId = 1234, - }; + "Test Sender", + "test_user_mention", + 1234); var embedsResponseTask = ((WatchdogBase)instanceReference.Watchdog).HandleChatCommand( "embeds_test", From 6d435b7fddf7facb1c566a9d72a7b9d71c642203 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:37:47 -0500 Subject: [PATCH 589/717] Re-enable control of random chat disconnections --- tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs | 4 ++-- tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs | 2 +- tests/Tgstation.Server.Tests/Live/TestLiveServer.cs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs index debbf913b82..872e59e6e65 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyChatProvider.cs @@ -55,10 +55,10 @@ static IAsyncDelayer CreateMockDelayer() return mock.Object; } - public static Task RandomDisconnections(bool enabled, CancellationToken cancellationToken) + public static void RandomDisconnections(bool enabled) { // we just don't do random disconnections when live testing these days, too many potential issue vectors like thread exhaustion on actions runners - return Task.CompletedTask; + enableRandomDisconnections = enabled ? 1 : 0; } public DummyChatProvider( diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs index 24e1dca4719..678ef10fc77 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs @@ -158,7 +158,7 @@ await Task.WhenAll( await TestDMApiFreeDeploy(cancellationToken); // long running test likes consistency with the channels - await DummyChatProvider.RandomDisconnections(false, cancellationToken); + DummyChatProvider.RandomDisconnections(false); await RunLongRunningTestThenUpdate(cancellationToken); diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 96ee8ba640e..9ac95ce865e 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -194,7 +194,7 @@ public static async Task Initialize(TestContext _) await CachingFileDownloader.InitializeAndInjectForLiveTests(default); - await DummyChatProvider.RandomDisconnections(true, default); + DummyChatProvider.RandomDisconnections(true); ServerClientFactory.ApiClientFactory = new RateLimitRetryingApiClientFactory(); var connectionString = Environment.GetEnvironmentVariable("TGS_TEST_CONNECTION_STRING"); @@ -1744,7 +1744,7 @@ await instanceClient.DreamDaemon.Update(new DreamDaemonRequest await chatTestObj.RunPostTest(cancellationToken); await repoTest; - await DummyChatProvider.RandomDisconnections(false, cancellationToken); + DummyChatProvider.RandomDisconnections(false); jobsHubTest.CompleteNow(); await jobsHubTestTask; From d5b69657f990ed4bf91e7a058426cf1cec82428f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Wed, 20 Dec 2023 23:55:08 -0500 Subject: [PATCH 590/717] Jobs can start will `null` `IInstanceCore`s --- src/Tgstation.Server.Host/Components/Instance.cs | 2 +- .../Controllers/DreamDaemonController.cs | 6 +++--- .../Controllers/DreamMakerController.cs | 2 +- src/Tgstation.Server.Host/Controllers/EngineController.cs | 4 ++-- .../Controllers/RepositoryController.cs | 4 ++-- src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs | 2 +- src/Tgstation.Server.Host/Jobs/JobService.cs | 4 +--- 7 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 10be9b18a31..8693e5cb265 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -266,7 +266,7 @@ public async ValueTask SetAutoUpdateInterval(uint newInterval) /// A representing the running operation. #pragma warning disable CA1502 // Cyclomatic complexity ValueTask RepositoryAutoUpdateJob( - IInstanceCore core, + IInstanceCore? core, IDatabaseContextFactory databaseContextFactory, Job job, JobProgressReporter progressReporter, diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index f83ec8410f5..069b272959b 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -90,7 +90,7 @@ public ValueTask Create(CancellationToken cancellationToken) var job = Job.Create(JobCode.WatchdogLaunch, AuthenticationContext.User, Instance, DreamDaemonRights.Shutdown); await jobManager.RegisterOperation( job, - (core, databaseContextFactory, paramJob, progressHandler, innerCt) => core.Watchdog.Launch(innerCt), + (core, databaseContextFactory, paramJob, progressHandler, innerCt) => core!.Watchdog.Launch(innerCt), cancellationToken); return Accepted(job.ToApi()); }); @@ -271,7 +271,7 @@ public ValueTask Restart(CancellationToken cancellationToken) await jobManager.RegisterOperation( job, - (core, paramJob, databaseContextFactory, progressReporter, ct) => core.Watchdog.Restart(false, ct), + (core, paramJob, databaseContextFactory, progressReporter, ct) => core!.Watchdog.Restart(false, ct), cancellationToken); return Accepted(job.ToApi()); }); @@ -297,7 +297,7 @@ public ValueTask CreateDump(CancellationToken cancellationToken) await jobManager.RegisterOperation( job, - (core, databaseContextFactory, paramJob, progressReporter, ct) => core.Watchdog.CreateDump(ct), + (core, databaseContextFactory, paramJob, progressReporter, ct) => core!.Watchdog.CreateDump(ct), cancellationToken); return Accepted(job.ToApi()); }); diff --git a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs index 680f8da7319..419bc9c90d7 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs @@ -151,7 +151,7 @@ public async ValueTask Create(CancellationToken cancellationToken await jobManager.RegisterOperation( job, (core, databaseContextFactory, paramJob, progressReporter, jobCancellationToken) - => core.DreamMaker.DeploymentProcess(paramJob, databaseContextFactory, progressReporter, jobCancellationToken), + => core!.DreamMaker.DeploymentProcess(paramJob, databaseContextFactory, progressReporter, jobCancellationToken), cancellationToken); return Accepted(job.ToApi()); } diff --git a/src/Tgstation.Server.Host/Controllers/EngineController.cs b/src/Tgstation.Server.Host/Controllers/EngineController.cs index 2f83a1afd86..d5072c597f3 100644 --- a/src/Tgstation.Server.Host/Controllers/EngineController.cs +++ b/src/Tgstation.Server.Host/Controllers/EngineController.cs @@ -245,7 +245,7 @@ await jobManager.RegisterOperation( } await using (zipFileStream) - await core.EngineManager.ChangeVersion( + await core!.EngineManager.ChangeVersion( progressHandler, model.EngineVersion, zipFileStream, @@ -329,7 +329,7 @@ public async ValueTask Delete([FromBody] EngineVersionDeleteReque await jobManager.RegisterOperation( job, (instanceCore, databaseContextFactory, job, progressReporter, jobCancellationToken) - => instanceCore.EngineManager.DeleteVersion(progressReporter, engineVersion, jobCancellationToken), + => instanceCore!.EngineManager.DeleteVersion(progressReporter, engineVersion, jobCancellationToken), cancellationToken); var apiResponse = job.ToApi(); diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs index dcff26b25e7..5d4d686aaf2 100644 --- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs +++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs @@ -151,7 +151,7 @@ await jobManager.RegisterOperation( job, async (core, databaseContextFactory, paramJob, progressReporter, ct) => { - var repoManager = core.RepositoryManager; + var repoManager = core!.RepositoryManager; using var repos = await repoManager.CloneRepository( origin, cloneBranch, @@ -217,7 +217,7 @@ public async ValueTask Delete(CancellationToken cancellationToken var api = currentModel.ToApi(); await jobManager.RegisterOperation( job, - (core, databaseContextFactory, paramJob, progressReporter, ct) => core.RepositoryManager.DeleteRepository(ct), + (core, databaseContextFactory, paramJob, progressReporter, ct) => core!.RepositoryManager.DeleteRepository(ct), cancellationToken); api.ActiveJob = job.ToApi(); return Accepted(api); diff --git a/src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs b/src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs index 79e71b5048c..82e81a647ce 100644 --- a/src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs +++ b/src/Tgstation.Server.Host/Jobs/JobEntrypoint.cs @@ -17,7 +17,7 @@ namespace Tgstation.Server.Host.Jobs /// The for the operation. /// A representing the running operation. public delegate ValueTask JobEntrypoint( - IInstanceCore instance, + IInstanceCore? instance, IDatabaseContextFactory databaseContextFactory, Job job, JobProgressReporter progressReporter, diff --git a/src/Tgstation.Server.Host/Jobs/JobService.cs b/src/Tgstation.Server.Host/Jobs/JobService.cs index 8db21d3068c..ea2782a8218 100644 --- a/src/Tgstation.Server.Host/Jobs/JobService.cs +++ b/src/Tgstation.Server.Host/Jobs/JobService.cs @@ -460,10 +460,8 @@ void UpdateProgress(string? stage, double? progress) QueueHubUpdate(job.ToApi(), false); logger.LogTrace("Starting job..."); - var instanceCore = instanceCoreProvider.GetInstance(job.Instance!) - ?? throw new JobException("Could not retrieve instance core for job!"); await operation( - instanceCore, + instanceCoreProvider.GetInstance(job.Instance!), databaseContextFactory, job, new JobProgressReporter( From 6eb6d730332f37e3b052a56ad760ad7aba153463 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 21 Dec 2023 08:24:02 -0500 Subject: [PATCH 591/717] Set `WarningLevel=0` for OD DMAPI build --- .github/workflows/ci-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 1efe65423b9..483a030d505 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -203,7 +203,7 @@ jobs: - name: Create TGS Deployment run: | cd $HOME/OpenDream - dotnet run -c Release --project OpenDreamPackageTool -- --tgs -o tgs_deploy + dotnet run -c Release --project OpenDreamPackageTool --property WarningLevel=0 -- --tgs -o tgs_deploy - name: Build DMAPI run: | From 30592dec0cfbcf7e4f422187c6432468a112a22f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 21 Dec 2023 09:05:00 -0500 Subject: [PATCH 592/717] Nullify `IChatManager` --- src/Tgstation.Server.Host/Components/Chat/ChatManager.cs | 4 ++-- src/Tgstation.Server.Host/Components/Chat/IChatManager.cs | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index 36812e77434..9c0ce9ffb09 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -380,8 +380,8 @@ public Func> QueueDeploymentMessage( Models.RevisionInformation revisionInformation, EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, - string gitHubOwner, - string gitHubRepo, + string? gitHubOwner, + string? gitHubRepo, bool localCommitPushed) { List wdChannels; diff --git a/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs index 435c867d3eb..e053f7f1de9 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Interop; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat { /// @@ -73,8 +71,8 @@ Func> QueueDeploymentMessage( Models.RevisionInformation revisionInformation, Api.Models.EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, - string gitHubOwner, - string gitHubRepo, + string? gitHubOwner, + string? gitHubRepo, bool localCommitPushed); /// From 921e7ddee074726bf80fcea3bc07d3d4b94cc759 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 21 Dec 2023 09:05:34 -0500 Subject: [PATCH 593/717] Nullify `IChatManagerFactory` --- .../Components/Chat/IChatManagerFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/IChatManagerFactory.cs b/src/Tgstation.Server.Host/Components/Chat/IChatManagerFactory.cs index 4af42411bee..bff29dc9c45 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChatManagerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChatManagerFactory.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Components.Chat.Commands; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat { /// From a1d1dda9af314dc5727ac7c4b4d82fb10d005632 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 21 Dec 2023 09:05:51 -0500 Subject: [PATCH 594/717] Nullify `IChatTrackingContext` --- .../Components/Chat/IChatTrackingContext.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/IChatTrackingContext.cs b/src/Tgstation.Server.Host/Components/Chat/IChatTrackingContext.cs index 284c0f5564e..37e1da9584b 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChatTrackingContext.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChatTrackingContext.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.Components.Chat.Commands; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat { /// From e677124bd5238391ebe60df1751cf21e0b3444aa Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 21 Dec 2023 09:06:04 -0500 Subject: [PATCH 595/717] Nullify `ICustomCommandHandler` --- .../Components/Chat/ICustomCommandHandler.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ICustomCommandHandler.cs b/src/Tgstation.Server.Host/Components/Chat/ICustomCommandHandler.cs index 988f3faa2f3..bf406bb4219 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ICustomCommandHandler.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ICustomCommandHandler.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.Components.Interop; -#nullable disable - namespace Tgstation.Server.Host.Components.Chat { /// From 31570e338a030c571cd3f1a1858bd1e06102a8a3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 21 Dec 2023 09:06:28 -0500 Subject: [PATCH 596/717] Move a comment slightly --- src/Tgstation.Server.Host/Components/Chat/ChatManager.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index 9c0ce9ffb09..3bedb438c80 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -24,8 +24,7 @@ namespace Tgstation.Server.Host.Components.Chat { /// - // TODO: Decomplexify -#pragma warning disable CA1506 +#pragma warning disable CA1506 // TODO: Decomplexify sealed class ChatManager : IChatManager, IRestartHandler { /// From ae89dc3eb71bf31598a64b93836fa787f868dd56 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 21 Dec 2023 09:08:29 -0500 Subject: [PATCH 597/717] Nullify `IRemoteDeploymentManager` --- .../Deployment/Remote/IRemoteDeploymentManager.cs | 8 +++----- src/Tgstation.Server.Host/Components/Instance.cs | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManager.cs index de92f3d31bc..e73f6a1063c 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManager.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment.Remote { /// @@ -36,7 +34,7 @@ ValueTask StartDeployment( /// A representing the running operation. ValueTask StageDeployment( CompileJob compileJob, - Action activationCallback, + Action? activationCallback, CancellationToken cancellationToken); /// @@ -70,8 +68,8 @@ ValueTask StageDeployment( /// The deployed . /// The of the previous deployment. /// The . - /// The GitHub repostiory owner. - /// The GitHub repostiory name. + /// The remote repostiory owner. + /// The remote repostiory name. /// The for the operation. /// A representing the running operation. ValueTask PostDeploymentComments( diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 8693e5cb265..9e6b2de4a58 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -387,7 +387,7 @@ async ValueTask UpdateRevInfo(string currentHead, bool onOrigin, IEnumerable Date: Thu, 21 Dec 2023 14:53:00 -0500 Subject: [PATCH 598/717] Fix messages in `BaseRemoteDeploymentManager` --- .../Remote/BaseRemoteDeploymentManager.cs | 72 ++++++++++--------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs index b06a3f86623..7822d290618 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs @@ -96,7 +96,7 @@ public async ValueTask PostDeploymentComments( .Any(y => y.TestMerge.Number == x.Number)) .ToList(); - if (!addedTestMerges.Any() && !removedTestMerges.Any() && !updatedTestMerges.Any()) + if (addedTestMerges.Count == 0 && removedTestMerges.Count == 0 && updatedTestMerges.Count == 0) return; Logger.LogTrace( @@ -107,48 +107,54 @@ public async ValueTask PostDeploymentComments( var tasks = new List(addedTestMerges.Count + updatedTestMerges.Count + removedTestMerges.Count); foreach (var addedTestMerge in addedTestMerges) - tasks.Add( - CommentOnTestMergeSource( + { + var addCommentTask = CommentOnTestMergeSource( + repositorySettings, + repoOwner, + repoName, + FormatTestMerge( repositorySettings, + compileJob, + addedTestMerge, repoOwner, repoName, - FormatTestMerge( - repositorySettings, - compileJob, - addedTestMerge, - repoOwner, - repoName, - false), - addedTestMerge.Number, - cancellationToken)); + false), + addedTestMerge.Number, + cancellationToken); + tasks.Add(addCommentTask); + } foreach (var removedTestMerge in removedTestMerges) - tasks.Add( - CommentOnTestMergeSource( - repositorySettings, - repoOwner, - repoName, - "#### Test Merge Removed", - removedTestMerge.Number, - cancellationToken)); + { + var removeCommentTask = CommentOnTestMergeSource( + repositorySettings, + repoOwner, + repoName, + "#### Test Merge Removed", + removedTestMerge.Number, + cancellationToken); + tasks.Add(removeCommentTask); + } foreach (var updatedTestMerge in updatedTestMerges) - tasks.Add( - CommentOnTestMergeSource( + { + var updateCommentTask = CommentOnTestMergeSource( + repositorySettings, + repoOwner, + repoName, + FormatTestMerge( repositorySettings, + compileJob, + updatedTestMerge, repoOwner, repoName, - FormatTestMerge( - repositorySettings, - compileJob, - updatedTestMerge, - repoOwner, - repoName, - true), - updatedTestMerge.Number, - cancellationToken)); - - if (tasks.Any()) + true), + updatedTestMerge.Number, + cancellationToken); + tasks.Add(updateCommentTask); + } + + if (tasks.Count > 0) await ValueTaskExtensions.WhenAll(tasks); } From 4d9be5bdd67d3c6b74020cfb86b71c2025c47739 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Thu, 21 Dec 2023 15:09:04 -0500 Subject: [PATCH 599/717] Nullify `BaseRemoteDeploymentManager` --- .../Remote/BaseRemoteDeploymentManager.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs index 7822d290618..a2aea1401c3 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs @@ -11,8 +11,6 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment.Remote { /// @@ -65,7 +63,7 @@ public async ValueTask PostDeploymentComments( var deployedRevisionInformation = compileJob.RevisionInformation; if ((previousRevisionInformation != null && previousRevisionInformation.CommitSha == deployedRevisionInformation.CommitSha) - || !repositorySettings.PostTestMergeComment.Value) + || !repositorySettings.PostTestMergeComment!.Value) return; previousRevisionInformation ??= new RevisionInformation(); @@ -163,7 +161,7 @@ public ValueTask ApplyDeployment(CompileJob compileJob, CancellationToken cancel { ArgumentNullException.ThrowIfNull(compileJob); - if (activationCallbacks.TryGetValue(compileJob.Id.Value, out var activationCallback)) + if (activationCallbacks.TryGetValue(compileJob.Require(x => x.Id), out var activationCallback)) activationCallback(true); return ApplyDeploymentImpl(compileJob, cancellationToken); @@ -177,7 +175,7 @@ public ValueTask MarkInactive(CompileJob compileJob, CancellationToken cancellat { ArgumentNullException.ThrowIfNull(compileJob); - if (activationCallbacks.TryRemove(compileJob.Id.Value, out var activationCallback)) + if (activationCallbacks.TryRemove(compileJob.Require(x => x.Id), out var activationCallback)) activationCallback(false); return MarkInactiveImpl(compileJob, cancellationToken); @@ -191,12 +189,13 @@ public abstract ValueTask> RemoveMergedTestMerges CancellationToken cancellationToken); /// - public ValueTask StageDeployment(CompileJob compileJob, Action activationCallback, CancellationToken cancellationToken) + public ValueTask StageDeployment(CompileJob compileJob, Action? activationCallback, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(compileJob); - if (activationCallback != null && !activationCallbacks.TryAdd(compileJob.Id.Value, activationCallback)) - Logger.LogError("activationCallbacks conflicted on CompileJob #{id}!", compileJob.Id.Value); + var compileJobId = compileJob.Require(x => x.Id); + if (activationCallback != null && !activationCallbacks.TryAdd(compileJobId, activationCallback)) + Logger.LogError("activationCallbacks conflicted on CompileJob #{id}!", compileJobId); return StageDeploymentImpl(compileJob, cancellationToken); } From 9a36a4fd2afc8b038e8e91f65b5724aadb9f5256 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:28:25 -0500 Subject: [PATCH 600/717] Nullify `GitHubRemoteDeploymentManager` --- .../Remote/GitHubRemoteDeploymentManager.cs | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs index 493daab039f..4e37e7d008b 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitHubRemoteDeploymentManager.cs @@ -17,8 +17,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Utils.GitHub; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment.Remote { /// @@ -67,7 +65,7 @@ public override async ValueTask StartDeployment( Logger.LogTrace("Starting deployment..."); - RepositorySettings repositorySettings = null; + RepositorySettings? repositorySettings = null; await databaseContextFactory.UseContext( async databaseContext => repositorySettings = await databaseContext @@ -76,12 +74,12 @@ await databaseContextFactory.UseContext( .Where(x => x.InstanceId == Metadata.Id) .FirstAsync(cancellationToken)); - var instanceAuthenticated = repositorySettings.AccessToken != null; - IAuthenticatedGitHubService authenticatedGitHubService; + var instanceAuthenticated = repositorySettings!.AccessToken != null; + IAuthenticatedGitHubService? authenticatedGitHubService; IGitHubService gitHubService; if (instanceAuthenticated) { - authenticatedGitHubService = gitHubServiceFactory.CreateService(repositorySettings.AccessToken); + authenticatedGitHubService = gitHubServiceFactory.CreateService(repositorySettings.AccessToken!); gitHubService = authenticatedGitHubService; } else @@ -90,12 +88,14 @@ await databaseContextFactory.UseContext( gitHubService = gitHubServiceFactory.CreateService(); } + var repoOwner = remoteInformation.RemoteRepositoryOwner!; + var repoName = remoteInformation.RemoteRepositoryName!; var repositoryIdTask = gitHubService.GetRepositoryId( - remoteInformation.RemoteRepositoryOwner, - remoteInformation.RemoteRepositoryName, + repoOwner, + repoName, cancellationToken); - if (!repositorySettings.CreateGitHubDeployments.Value) + if (!repositorySettings.CreateGitHubDeployments!.Value) Logger.LogTrace("Not creating deployment"); else if (!instanceAuthenticated) Logger.LogWarning("Can't create GitHub deployment as no access token is set for repository!"); @@ -104,7 +104,7 @@ await databaseContextFactory.UseContext( Logger.LogTrace("Creating deployment..."); try { - compileJob.GitHubDeploymentId = await authenticatedGitHubService.CreateDeployment( + compileJob.GitHubDeploymentId = await authenticatedGitHubService!.CreateDeployment( new NewDeployment(compileJob.RevisionInformation.CommitSha) { AutoMerge = false, @@ -113,8 +113,8 @@ await databaseContextFactory.UseContext( ProductionEnvironment = true, RequiredContexts = new Collection(), }, - remoteInformation.RemoteRepositoryOwner, - remoteInformation.RemoteRepositoryName, + repoOwner, + repoName, cancellationToken); Logger.LogDebug("Created deployment ID {deploymentId}", compileJob.GitHubDeploymentId); @@ -125,8 +125,8 @@ await authenticatedGitHubService.CreateDeploymentStatus( Description = "The project is being deployed", AutoInactive = false, }, - remoteInformation.RemoteRepositoryOwner, - remoteInformation.RemoteRepositoryName, + repoOwner, + repoName, compileJob.GitHubDeploymentId.Value, cancellationToken); @@ -168,7 +168,7 @@ public override async ValueTask> RemoveMergedTest ArgumentNullException.ThrowIfNull(repositorySettings); ArgumentNullException.ThrowIfNull(revisionInformation); - if (revisionInformation.ActiveTestMerges?.Any() != true) + if ((revisionInformation.ActiveTestMerges?.Count > 0) != true) { Logger.LogTrace("No test merges to remove."); return Array.Empty(); @@ -180,7 +180,11 @@ public override async ValueTask> RemoveMergedTest var tasks = revisionInformation .ActiveTestMerges - .Select(x => gitHubService.GetPullRequest(repository.RemoteRepositoryOwner, repository.RemoteRepositoryName, x.TestMerge.Number, cancellationToken)); + .Select(x => gitHubService.GetPullRequest( + repository.RemoteRepositoryOwner!, + repository.RemoteRepositoryName!, + x.TestMerge.Number, + cancellationToken)); try { await Task.WhenAll(tasks); @@ -192,7 +196,7 @@ public override async ValueTask> RemoveMergedTest var newList = revisionInformation.ActiveTestMerges.Select(x => x.TestMerge).ToList(); - PullRequest lastMerged = null; + PullRequest? lastMerged = null; async ValueTask CheckRemovePR(Task task) { var pr = await task; @@ -251,7 +255,7 @@ protected override async ValueTask CommentOnTestMergeSource( int testMergeNumber, CancellationToken cancellationToken) { - var gitHubService = gitHubServiceFactory.CreateService(repositorySettings.AccessToken); + var gitHubService = gitHubServiceFactory.CreateService(repositorySettings.AccessToken!); try { @@ -274,12 +278,12 @@ protected override string FormatTestMerge( CultureInfo.InvariantCulture, "#### Test Merge {4}{0}{0}
Details{0}{0}##### Server Instance{0}{5}{1}{0}{0}##### Revision{0}Origin: {6}{0}Pull Request: {2}{0}Server: {7}{3}{8}{0}
", Environment.NewLine, - repositorySettings.ShowTestMergeCommitters.Value + repositorySettings.ShowTestMergeCommitters!.Value ? String.Format( CultureInfo.InvariantCulture, "{0}{0}##### Merged By{0}{1}", Environment.NewLine, - testMerge.MergedBy.Name) + testMerge.MergedBy!.Name) : String.Empty, testMerge.TargetCommitSha, testMerge.Comment != null @@ -294,7 +298,7 @@ protected override string FormatTestMerge( compileJob.RevisionInformation.OriginCommitSha, compileJob.RevisionInformation.CommitSha, compileJob.GitHubDeploymentId.HasValue - ? $"{Environment.NewLine}[GitHub Deployments](https://github.com/{remoteRepositoryOwner}/{remoteRepositoryName}/deployments/activity_log?environment=TGS%3A+{Metadata.Name.Replace(" ", "+", StringComparison.Ordinal)})" + ? $"{Environment.NewLine}[GitHub Deployments](https://github.com/{remoteRepositoryOwner}/{remoteRepositoryName}/deployments/activity_log?environment=TGS%3A+{Metadata.Name!.Replace(" ", "+", StringComparison.Ordinal)})" : String.Empty); /// @@ -321,7 +325,7 @@ async ValueTask UpdateDeployment( Logger.LogTrace("Updating deployment {gitHubDeploymentId} to {deploymentState}...", compileJob.GitHubDeploymentId.Value, deploymentState); - string gitHubAccessToken = null; + string? gitHubAccessToken = null; await databaseContextFactory.UseContext( async databaseContext => gitHubAccessToken = await databaseContext From a48000711fd8820096eea49445b4e5421955d450 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:36:40 -0500 Subject: [PATCH 601/717] Nullify `GitLabRemoteDeploymentManager` --- .../Deployment/Remote/GitLabRemoteDeploymentManager.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs index 0190d0c9936..9d0adeaf37f 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/GitLabRemoteDeploymentManager.cs @@ -14,8 +14,6 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment.Remote { /// @@ -48,7 +46,7 @@ public override async ValueTask> RemoveMergedTest ArgumentNullException.ThrowIfNull(repositorySettings); ArgumentNullException.ThrowIfNull(revisionInformation); - if (revisionInformation.ActiveTestMerges?.Any() != true) + if ((revisionInformation.ActiveTestMerges?.Count > 0) != true) { Logger.LogTrace("No test merges to remove."); return Array.Empty(); @@ -77,7 +75,7 @@ public override async ValueTask> RemoveMergedTest var newList = revisionInformation.ActiveTestMerges.Select(x => x.TestMerge).ToList(); - MergeRequest lastMerged = null; + MergeRequest? lastMerged = null; async ValueTask CheckRemoveMR(Task task) { var mergeRequest = await task; @@ -164,12 +162,12 @@ protected override string FormatTestMerge( CultureInfo.InvariantCulture, "#### Test Merge {4}{0}{0}##### Server Instance{0}{5}{1}{0}{0}##### Revision{0}Origin: {6}{0}Merge Request: {2}{0}Server: {7}{3}", Environment.NewLine, - repositorySettings.ShowTestMergeCommitters.Value + repositorySettings.ShowTestMergeCommitters!.Value ? String.Format( CultureInfo.InvariantCulture, "{0}{0}##### Merged By{0}{1}", Environment.NewLine, - testMerge.MergedBy.Name) + testMerge.MergedBy!.Name) : String.Empty, testMerge.TargetCommitSha, testMerge.Comment != null From 16e95b375613fbeeb88adceb9dd27a1dd2c60b26 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:37:31 -0500 Subject: [PATCH 602/717] Nullify `IRemoteDeploymentManagerFactory` --- .../Deployment/Remote/IRemoteDeploymentManagerFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManagerFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManagerFactory.cs index 129d5aa35a8..b3dce1f69c1 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManagerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManagerFactory.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Api.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment.Remote { /// From b17693d8b34a3b780b76f66d5f34bd965816e17f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:37:50 -0500 Subject: [PATCH 603/717] Nullify `NoOpRemoteDeploymentManager` --- .../Components/Deployment/Remote/NoOpRemoteDeploymentManager.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/NoOpRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/NoOpRemoteDeploymentManager.cs index 250b43bddf3..6751f181849 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/NoOpRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/NoOpRemoteDeploymentManager.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment.Remote { /// From 5be5c4e0ef0ed07581b64be30f636f4df1e65a41 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:38:15 -0500 Subject: [PATCH 604/717] Nullify `RemoteDeploymentManagerFactory` --- .../Deployment/Remote/RemoteDeploymentManagerFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/RemoteDeploymentManagerFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/RemoteDeploymentManagerFactory.cs index d525d3dffe3..0fdce864cf9 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/RemoteDeploymentManagerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/RemoteDeploymentManagerFactory.cs @@ -9,8 +9,6 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Utils.GitHub; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment.Remote { /// From fde9e5026803298ccc5c60e1856c3525777c3b9d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:39:20 -0500 Subject: [PATCH 605/717] Nullify `ILatestCompileJobProvider` --- .../Components/Deployment/ILatestCompileJobProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/ILatestCompileJobProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/ILatestCompileJobProvider.cs index d60ac9ad314..38a90c8dc60 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/ILatestCompileJobProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/ILatestCompileJobProvider.cs @@ -1,7 +1,5 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// From dd971fe56beb4fcfd3b3026a50e1dc55438ee369 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:39:59 -0500 Subject: [PATCH 606/717] Nullify `ICompileJobSink` --- .../Components/Deployment/ICompileJobSink.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/ICompileJobSink.cs b/src/Tgstation.Server.Host/Components/Deployment/ICompileJobSink.cs index 90a0f1596c8..cf18fc04121 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/ICompileJobSink.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/ICompileJobSink.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// @@ -17,9 +15,9 @@ public interface ICompileJobSink : ILatestCompileJobProvider /// Load a new into the . /// /// The to load. - /// An to be called when the becomes active or is discarded with or respectively. + /// An optional to be called when the becomes active or is discarded with or respectively. /// The for the operation. /// A representing the running operation. - ValueTask LoadCompileJob(CompileJob job, Action activationAction, CancellationToken cancellationToken); + ValueTask LoadCompileJob(CompileJob job, Action? activationAction, CancellationToken cancellationToken); } } From fb6704937f567f3c9629e07a787bd0afa4e3755f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:40:24 -0500 Subject: [PATCH 607/717] Nullify `IDmbProvider` --- src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs index 20ef72dd331..820796c3186 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/IDmbProvider.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Api.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// From 7e15cc1ad29279d7cdaabf8b9cc6393b50a45622 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:40:43 -0500 Subject: [PATCH 608/717] Nullify `IDreamMaker` --- src/Tgstation.Server.Host/Components/Deployment/IDreamMaker.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/IDreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/IDreamMaker.cs index b9e8f4e88ad..32443080165 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/IDreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/IDreamMaker.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// From d2ee58740ffedc949fb71f937ed8c764dc11d0cd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:41:06 -0500 Subject: [PATCH 609/717] Nullify `IDmbFactory` --- src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs index a6c31736770..6ff04b0a00f 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// From 358e6ca1c83f48c4b594ef251ca113f3a84ffd84 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:42:26 -0500 Subject: [PATCH 610/717] Fix IDE messages in `DmbFactory` --- .../Components/Deployment/DmbFactory.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs index 3e969409b40..d5dd1f13bde 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs @@ -76,7 +76,7 @@ public Task OnNewerDmb /// /// Map of s to locks on them. /// - readonly IDictionary jobLockCounts; + readonly Dictionary jobLockCounts; /// /// resulting in the latest yet to exist. @@ -255,7 +255,7 @@ await databaseContextFactory.UseContext( if (!EngineVersion.TryParse(compileJob.EngineVersion, out var engineVersion)) { - logger.LogWarning("Error loading compile job, bad engine version: {0}", compileJob.EngineVersion); + logger.LogWarning("Error loading compile job, bad engine version: {engineVersion}", compileJob.EngineVersion); return null; // omae wa mou shinderu } @@ -353,7 +353,7 @@ public async ValueTask CleanUnusedCompileJobs(CancellationToken cancellationToke List jobUidsToNotErase = null; // find the uids of locked directories - if (jobIdsToSkip.Any()) + if (jobIdsToSkip.Count > 0) { await databaseContextFactory.UseContext(async db => { From 707d69d2e658caaba3272f309649e9e32be2ae04 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:48:24 -0500 Subject: [PATCH 611/717] Nullify `DmbFactory` --- .../Components/Deployment/DmbFactory.cs | 93 ++++++++++--------- .../Components/Deployment/IDmbFactory.cs | 4 +- .../Deployment/ILatestCompileJobProvider.cs | 4 +- .../Components/Instance.cs | 2 +- .../Components/InstanceWrapper.cs | 2 +- 5 files changed, 54 insertions(+), 51 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs index d5dd1f13bde..aebfcda51a7 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Threading; @@ -16,8 +17,6 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// @@ -36,6 +35,7 @@ public Task OnNewerDmb } /// + [MemberNotNullWhen(true, nameof(nextDmbProvider))] public bool DmbAvailable => nextDmbProvider != null; /// @@ -91,7 +91,7 @@ public Task OnNewerDmb /// /// The latest . /// - IDmbProvider nextDmbProvider; + IDmbProvider? nextDmbProvider; /// /// If the is "started" via . @@ -132,7 +132,7 @@ public DmbFactory( public void Dispose() => cleanupCts.Dispose(); // we don't dispose nextDmbProvider here, since it might be the only thing we have /// - public async ValueTask LoadCompileJob(CompileJob job, Action activationAction, CancellationToken cancellationToken) + public async ValueTask LoadCompileJob(CompileJob job, Action? activationAction, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(job); @@ -175,8 +175,8 @@ public IDmbProvider LockNextDmb(int lockCount) throw new ArgumentOutOfRangeException(nameof(lockCount), lockCount, "lockCount must be greater than or equal to 0!"); lock (jobLockCounts) { - var jobId = nextDmbProvider.CompileJob.Id; - var incremented = jobLockCounts[jobId.Value] += lockCount; + var jobId = nextDmbProvider.CompileJob.Require(x => x.Id); + var incremented = jobLockCounts[jobId] += lockCount; logger.LogTrace("Compile job {jobId} lock count now: {lockCount}", jobId, incremented); return nextDmbProvider; } @@ -185,16 +185,15 @@ public IDmbProvider LockNextDmb(int lockCount) /// public async Task StartAsync(CancellationToken cancellationToken) { - CompileJob cj = null; - await databaseContextFactory.UseContext(async (db) => - { - cj = await db - .CompileJobs - .AsQueryable() - .Where(x => x.Job.Instance.Id == metadata.Id) - .OrderByDescending(x => x.Job.StoppedAt) - .FirstOrDefaultAsync(cancellationToken); - }); + CompileJob? cj = null; + await databaseContextFactory.UseContext( + async (db) => + cj = await db + .CompileJobs + .AsQueryable() + .Where(x => x.Job.Instance!.Id == metadata.Id) + .OrderByDescending(x => x.Job.StoppedAt) + .FirstOrDefaultAsync(cancellationToken)); try { @@ -229,28 +228,29 @@ public async Task StopAsync(CancellationToken cancellationToken) /// #pragma warning disable CA1506 // TODO: Decomplexify - public async ValueTask FromCompileJob(CompileJob compileJob, CancellationToken cancellationToken) + public async ValueTask FromCompileJob(CompileJob compileJob, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(compileJob); // ensure we have the entire metadata tree - logger.LogTrace("Loading compile job {id}...", compileJob.Id); + var compileJobId = compileJob.Require(x => x.Id); + logger.LogTrace("Loading compile job {id}...", compileJobId); await databaseContextFactory.UseContext( async db => compileJob = await db .CompileJobs .AsQueryable() - .Where(x => x.Id == compileJob.Id) - .Include(x => x.Job) + .Where(x => x!.Id == compileJobId) + .Include(x => x.Job!) .ThenInclude(x => x.StartedBy) - .Include(x => x.Job) + .Include(x => x.Job!) .ThenInclude(x => x.Instance) - .Include(x => x.RevisionInformation) - .ThenInclude(x => x.PrimaryTestMerge) - .ThenInclude(x => x.MergedBy) - .Include(x => x.RevisionInformation) - .ThenInclude(x => x.ActiveTestMerges) - .ThenInclude(x => x.TestMerge) - .ThenInclude(x => x.MergedBy) + .Include(x => x.RevisionInformation!) + .ThenInclude(x => x.PrimaryTestMerge!) + .ThenInclude(x => x.MergedBy) + .Include(x => x.RevisionInformation!) + .ThenInclude(x => x.ActiveTestMerges!) + .ThenInclude(x => x.TestMerge!) + .ThenInclude(x => x.MergedBy) .FirstAsync(cancellationToken)); // can't wait to see that query if (!EngineVersion.TryParse(compileJob.EngineVersion, out var engineVersion)) @@ -318,17 +318,17 @@ void CleanupAction() lock (jobLockCounts) { - if (!jobLockCounts.TryGetValue(compileJob.Id.Value, out int value)) + if (!jobLockCounts.TryGetValue(compileJobId, out int value)) { value = 1; - jobLockCounts.Add(compileJob.Id.Value, 1); + jobLockCounts.Add(compileJobId, 1); } else - jobLockCounts[compileJob.Id.Value] = ++value; + jobLockCounts[compileJobId] = ++value; providerSubmitted = true; - logger.LogTrace("Compile job {id} lock count now: {lockCount}", compileJob.Id, value); + logger.LogTrace("Compile job {id} lock count now: {lockCount}", compileJobId, value); return newProvider; } } @@ -350,7 +350,7 @@ public async ValueTask CleanUnusedCompileJobs(CancellationToken cancellationToke lock (jobLockCounts) jobIdsToSkip = jobLockCounts.Keys.ToList(); - List jobUidsToNotErase = null; + List? jobUidsToNotErase = null; // find the uids of locked directories if (jobIdsToSkip.Count > 0) @@ -361,9 +361,9 @@ await databaseContextFactory.UseContext(async db => .CompileJobs .AsQueryable() .Where( - x => x.Job.Instance.Id == metadata.Id - && jobIdsToSkip.Contains(x.Id.Value)) - .Select(x => x.DirectoryName.Value) + x => x.Job.Instance!.Id == metadata.Id + && jobIdsToSkip.Contains(x.Id!.Value)) + .Select(x => x.DirectoryName!.Value) .ToListAsync(cancellationToken)) .Select(x => x.ToString()) .ToList(); @@ -372,7 +372,7 @@ await databaseContextFactory.UseContext(async db => else jobUidsToNotErase = new List(); - jobUidsToNotErase.Add(SwappableDmbProvider.LiveGameDirectory); + jobUidsToNotErase!.Add(SwappableDmbProvider.LiveGameDirectory); logger.LogTrace("We will not clean the following directories: {directoriesToNotClean}", String.Join(", ", jobUidsToNotErase)); @@ -407,7 +407,7 @@ await databaseContextFactory.UseContext(async db => #pragma warning restore CA1506 /// - public CompileJob LatestCompileJob() + public CompileJob? LatestCompileJob() { if (!DmbAvailable) return null; @@ -428,7 +428,7 @@ async Task HandleCleanup() // DCT: None available var deploymentJob = remoteDeploymentManager.MarkInactive(job, CancellationToken.None); - var deleteTask = DeleteCompileJobContent(job.DirectoryName.ToString(), cleanupCts.Token); + var deleteTask = DeleteCompileJobContent(job.DirectoryName!.Value.ToString(), cleanupCts.Token); var otherTask = cleanupTask; async Task WrapThrowableTasks() @@ -447,20 +447,23 @@ async Task WrapThrowableTasks() } lock (jobLockCounts) - if (jobLockCounts.TryGetValue(job.Id.Value, out var currentVal)) + { + var jobId = job.Require(x => x.Id); + if (jobLockCounts.TryGetValue(jobId, out var currentVal)) if (currentVal == 1) { - jobLockCounts.Remove(job.Id.Value); - logger.LogDebug("Cleaning lock-free compile job {id} => {dirName}", job.Id, job.DirectoryName); + jobLockCounts.Remove(jobId); + logger.LogDebug("Cleaning lock-free compile job {id} => {dirName}", jobId, job.DirectoryName); cleanupTask = HandleCleanup(); } else { - var decremented = --jobLockCounts[job.Id.Value]; - logger.LogTrace("Compile job {id} lock count now: {lockCount}", job.Id, decremented); + var decremented = --jobLockCounts[jobId]; + logger.LogTrace("Compile job {id} lock count now: {lockCount}", jobId, decremented); } else - logger.LogError("Extra Dispose of DmbProvider for CompileJob {compileJobId}!", job.Id); + logger.LogError("Extra Dispose of DmbProvider for CompileJob {compileJobId}!", jobId); + } } /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs index 6ff04b0a00f..08d1a782b54 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs @@ -23,7 +23,7 @@ public interface IDmbFactory : ILatestCompileJobProvider, IComponentService, IDi bool DmbAvailable { get; } /// - /// Gets the next . + /// Gets the next . is a precondition. /// /// The amount of locks to give the resulting . It's must be called this many times to properly clean the job. /// A new . @@ -35,7 +35,7 @@ public interface IDmbFactory : ILatestCompileJobProvider, IComponentService, IDi /// The to make the for. /// The for the operation. /// A resulting in a new representing the on success, on failure. - ValueTask FromCompileJob(CompileJob compileJob, CancellationToken cancellationToken); + ValueTask FromCompileJob(CompileJob compileJob, CancellationToken cancellationToken); /// /// Deletes all compile jobs that are inactive in the Game folder. diff --git a/src/Tgstation.Server.Host/Components/Deployment/ILatestCompileJobProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/ILatestCompileJobProvider.cs index 38a90c8dc60..021f62602d7 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/ILatestCompileJobProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/ILatestCompileJobProvider.cs @@ -10,7 +10,7 @@ public interface ILatestCompileJobProvider /// /// Gets the latest . /// - /// The latest . - CompileJob LatestCompileJob(); + /// The latest or if none are available. + CompileJob? LatestCompileJob(); } } diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 9e6b2de4a58..38932c52775 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -253,7 +253,7 @@ public async ValueTask SetAutoUpdateInterval(uint newInterval) } /// - public CompileJob LatestCompileJob() => dmbFactory.LatestCompileJob(); + public CompileJob? LatestCompileJob() => dmbFactory.LatestCompileJob(); /// /// The for updating the repository. diff --git a/src/Tgstation.Server.Host/Components/InstanceWrapper.cs b/src/Tgstation.Server.Host/Components/InstanceWrapper.cs index 5c525d98698..ba2c84d6880 100644 --- a/src/Tgstation.Server.Host/Components/InstanceWrapper.cs +++ b/src/Tgstation.Server.Host/Components/InstanceWrapper.cs @@ -58,6 +58,6 @@ public InstanceWrapper() public ValueTask SetAutoUpdateInterval(uint newInterval) => Instance.SetAutoUpdateInterval(newInterval); /// - public CompileJob LatestCompileJob() => Instance.LatestCompileJob(); + public CompileJob? LatestCompileJob() => Instance.LatestCompileJob(); } } From 083f7ca85ec7cc0d9dcd5faf355c46026456eabb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:53:15 -0500 Subject: [PATCH 612/717] Nullify `DmbProvider` --- .../Components/Deployment/DmbFactory.cs | 5 ++++- .../Components/Deployment/DmbProvider.cs | 8 +++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs index aebfcda51a7..0c5c43d31ee 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs @@ -253,11 +253,14 @@ await databaseContextFactory.UseContext( .ThenInclude(x => x.MergedBy) .FirstAsync(cancellationToken)); // can't wait to see that query - if (!EngineVersion.TryParse(compileJob.EngineVersion, out var engineVersion)) + EngineVersion engineVersion; + if (!EngineVersion.TryParse(compileJob.EngineVersion, out var engineVersionNullable)) { logger.LogWarning("Error loading compile job, bad engine version: {engineVersion}", compileJob.EngineVersion); return null; // omae wa mou shinderu } + else + engineVersion = engineVersionNullable!; if (!compileJob.Job.StoppedAt.HasValue) { diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs index 359fc615e20..4a21e4e8d2c 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs @@ -5,15 +5,13 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// sealed class DmbProvider : DmbProviderBase, IDmbProvider { /// - public override string Directory => ioManager.ResolvePath(CompileJob.DirectoryName.ToString() + directoryAppend); + public override string Directory => ioManager.ResolvePath(CompileJob.DirectoryName!.Value.ToString() + directoryAppend); /// public override Models.CompileJob CompileJob { get; } @@ -34,7 +32,7 @@ sealed class DmbProvider : DmbProviderBase, IDmbProvider /// /// The to run when is called. /// - Action onDispose; + Action? onDispose; /// /// Initializes a new instance of the class. @@ -44,7 +42,7 @@ sealed class DmbProvider : DmbProviderBase, IDmbProvider /// The value of . /// The value of . /// The optional value of . - public DmbProvider(Models.CompileJob compileJob, EngineVersion engineVersion, IIOManager ioManager, Action onDispose, string directoryAppend = null) + public DmbProvider(Models.CompileJob compileJob, EngineVersion engineVersion, IIOManager ioManager, Action onDispose, string? directoryAppend = null) { CompileJob = compileJob ?? throw new ArgumentNullException(nameof(compileJob)); EngineVersion = engineVersion ?? throw new ArgumentNullException(nameof(engineVersion)); From dba8721f3ead686f54de8235012a10218ee99c25 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 09:54:13 -0500 Subject: [PATCH 613/717] Nullify `DmbProviderBase` --- .../Components/Deployment/DmbProviderBase.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs index cdc57215ac1..5929b74167b 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbProviderBase.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// @@ -15,11 +13,11 @@ abstract class DmbProviderBase : IDmbProvider /// public string DmbName => String.Concat( CompileJob.DmeName, - EngineVersion.Engine.Value switch + EngineVersion.Engine switch { EngineType.Byond => ".dmb", EngineType.OpenDream => ".json", - _ => throw new InvalidOperationException($"Invalid EngineType: {EngineVersion.Engine.Value}"), + _ => throw new InvalidOperationException($"Invalid EngineType: {EngineVersion.Engine}"), }); /// From 7db53b03712c59db6e5c3a434d98eae91cbb514e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 10:04:14 -0500 Subject: [PATCH 614/717] Nullify `DreamMaker` --- .../Components/Chat/ChatManager.cs | 6 +- .../Components/Chat/IChatManager.cs | 2 +- .../Chat/Providers/DiscordProvider.cs | 2 +- .../Components/Chat/Providers/IProvider.cs | 2 +- .../Components/Chat/Providers/IrcProvider.cs | 2 +- .../Components/Chat/Providers/Provider.cs | 2 +- .../Components/Deployment/DreamMaker.cs | 93 +++++++++---------- .../Remote/BaseRemoteDeploymentManager.cs | 13 ++- .../Remote/IRemoteDeploymentManager.cs | 8 +- 9 files changed, 67 insertions(+), 63 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index 3bedb438c80..d53e997b256 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -375,7 +375,7 @@ public void QueueWatchdogMessage(string message) } /// - public Func> QueueDeploymentMessage( + public Func> QueueDeploymentMessage( Models.RevisionInformation revisionInformation, EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, @@ -389,7 +389,7 @@ public Func> QueueDeploymentMessage( logger.LogTrace("Sending deployment message for RevisionInformation: {revisionInfoId}", revisionInformation.Id); - var callbacks = new List>>>(); + var callbacks = new List>>>(); var task = Task.WhenAll( wdChannels.Select( @@ -431,7 +431,7 @@ public Func> QueueDeploymentMessage( Task callbackTask; Func? finalUpdateAction = null; - async Task CallbackTask(string errorMessage, string dreamMakerOutput) + async Task CallbackTask(string? errorMessage, string dreamMakerOutput) { await task; var callbackResults = await ValueTaskExtensions.WhenAll( diff --git a/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs index e053f7f1de9..8a0aa33fe4b 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChatManager.cs @@ -67,7 +67,7 @@ public interface IChatManager : IComponentService, IAsyncDisposable /// The repository GitHub name, if any. /// if the local deployment commit was pushed to the remote repository. /// A to call to update the message at the deployment's conclusion. Parameters: Error message if any, DreamMaker output if any. Returns an to call to mark the deployment as active/inactive. Parameter: If the deployment is being activated or inactivated. - Func> QueueDeploymentMessage( + Func> QueueDeploymentMessage( Models.RevisionInformation revisionInformation, Api.Models.EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 6d06322dfc8..047febbe00f 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -285,7 +285,7 @@ await ValueTaskExtensions.WhenAll( } /// - public override async ValueTask>>> SendUpdateMessage( + public override async ValueTask>>> SendUpdateMessage( Models.RevisionInformation revisionInformation, EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs index 01b0d29a5e8..845892d9e09 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs @@ -92,7 +92,7 @@ interface IProvider : IAsyncDisposable /// if the local deployment commit was pushed to the remote repository. /// The for the operation. /// A resulting in a to call to update the message at the deployment's conclusion. Parameters: Error message if any, DreamMaker output if any. Returns another callback which should be called to mark the deployment as active. - ValueTask>>> SendUpdateMessage( + ValueTask>>> SendUpdateMessage( Models.RevisionInformation revisionInformation, Api.Models.EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index f8dfec41975..ad83a80b18b 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -218,7 +218,7 @@ await Task.Factory.StartNew( } /// - public override async ValueTask>>> SendUpdateMessage( + public override async ValueTask>>> SendUpdateMessage( Models.RevisionInformation revisionInformation, EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs index 4123521ad79..6be6b715210 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs @@ -197,7 +197,7 @@ public Task SetReconnectInterval(uint reconnectInterval, bool connectNow) public abstract ValueTask SendMessage(Message? replyTo, MessageContent message, ulong channelId, CancellationToken cancellationToken); /// - public abstract ValueTask>>> SendUpdateMessage( + public abstract ValueTask>>> SendUpdateMessage( RevisionInformation revisionInformation, Api.Models.EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs index 89f69f7d7b0..f72d848082f 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs @@ -25,8 +25,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// @@ -115,12 +113,12 @@ sealed class DreamMaker : IDreamMaker /// /// The active callback from . /// - Func> currentChatCallback; + Func>? currentChatCallback; /// /// Cached for . /// - string currentDreamMakerOutput; + string? currentDreamMakerOutput; /// /// If a compile job is running. @@ -209,18 +207,18 @@ public async ValueTask DeploymentProcess( currentChatCallback = null; currentDreamMakerOutput = null; - Models.CompileJob compileJob = null; + Models.CompileJob? compileJob = null; try { - string repoOwner = null; - string repoName = null; + string? repoOwner = null; + string? repoName = null; TimeSpan? averageSpan = null; - Models.RepositorySettings repositorySettings = null; - Models.DreamDaemonSettings ddSettings = null; - Models.DreamMakerSettings dreamMakerSettings = null; - IRepository repo = null; - IRemoteDeploymentManager remoteDeploymentManager = null; - Models.RevisionInformation revInfo = null; + Models.RepositorySettings? repositorySettings = null; + Models.DreamDaemonSettings? ddSettings = null; + Models.DreamMakerSettings? dreamMakerSettings = null; + IRepository? repo = null; + IRemoteDeploymentManager? remoteDeploymentManager = null; + Models.RevisionInformation? revInfo = null; await databaseContextFactory.UseContext( async databaseContext => { @@ -270,7 +268,7 @@ await databaseContextFactory.UseContext( throw new JobException(ErrorCode.RepoMissing); remoteDeploymentManager = remoteDeploymentManagerFactory - .CreateRemoteDeploymentManager(metadata, repo.RemoteGitProvider.Value); + .CreateRemoteDeploymentManager(metadata, repo.RemoteGitProvider!.Value); var repoSha = repo.Head; repoOwner = repo.RemoteRepositoryOwner; @@ -278,13 +276,13 @@ await databaseContextFactory.UseContext( revInfo = await databaseContext .RevisionInformations .AsQueryable() - .Where(x => x.CommitSha == repoSha && x.Instance.Id == metadata.Id) - .Include(x => x.ActiveTestMerges) - .ThenInclude(x => x.TestMerge) - .ThenInclude(x => x.MergedBy) + .Where(x => x.CommitSha == repoSha && x.InstanceId == metadata.Id) + .Include(x => x.ActiveTestMerges!) + .ThenInclude(x => x.TestMerge!) + .ThenInclude(x => x.MergedBy) .FirstOrDefaultAsync(cancellationToken); - if (revInfo == default) + if (revInfo == null) { revInfo = new Models.RevisionInformation { @@ -312,17 +310,17 @@ await databaseContextFactory.UseContext( }); var likelyPushedTestMergeCommit = - repositorySettings.PushTestMergeCommits.Value + repositorySettings!.PushTestMergeCommits!.Value && repositorySettings.AccessToken != null && repositorySettings.AccessUser != null; using (repo) compileJob = await Compile( job, - revInfo, - dreamMakerSettings, - ddSettings, - repo, - remoteDeploymentManager, + revInfo!, + dreamMakerSettings!, + ddSettings!, + repo!, + remoteDeploymentManager!, progressReporter, averageSpan, likelyPushedTestMergeCommit, @@ -335,11 +333,11 @@ await databaseContextFactory.UseContext( async databaseContext => { var fullJob = compileJob.Job; - compileJob.Job = new Models.Job(job.Id.Value); + compileJob.Job = new Models.Job(job.Require(x => x.Id)); var fullRevInfo = compileJob.RevisionInformation; compileJob.RevisionInformation = new Models.RevisionInformation { - Id = revInfo.Id, + Id = revInfo!.Id, }; databaseContext.Jobs.Attach(compileJob.Job); @@ -351,7 +349,7 @@ await databaseContextFactory.UseContext( logger.LogTrace("Created CompileJob {compileJobId}", compileJob.Id); try { - var chatNotificationAction = currentChatCallback(null, compileJob.Output); + var chatNotificationAction = currentChatCallback!(null, compileJob.Output!); await compileJobConsumer.LoadCompileJob(compileJob, chatNotificationAction, cancellationToken); } catch @@ -370,11 +368,11 @@ await databaseContextFactory.UseContext( } catch (Exception ex) { - await CleanupFailedCompile(compileJob, remoteDeploymentManager, ex); + await CleanupFailedCompile(compileJob, remoteDeploymentManager!, ex); throw; } - var commentsTask = remoteDeploymentManager.PostDeploymentComments( + var commentsTask = remoteDeploymentManager!.PostDeploymentComments( compileJob, activeCompileJob?.RevisionInformation, repositorySettings, @@ -401,7 +399,7 @@ await databaseContextFactory.UseContext( { currentChatCallback?.Invoke( FormatExceptionForUsers(ex), - currentDreamMakerOutput); + currentDreamMakerOutput!); throw; } @@ -423,13 +421,13 @@ await databaseContextFactory.UseContext( var previousCompileJobs = await databaseContext .CompileJobs .AsQueryable() - .Where(x => x.Job.Instance.Id == metadata.Id) + .Where(x => x.Job.Instance!.Id == metadata.Id) .OrderByDescending(x => x.Job.StoppedAt) .Take(10) .Select(x => new { - x.Job.StoppedAt, - x.Job.StartedAt, + StoppedAt = x.Job.StoppedAt!.Value, + StartedAt = x.Job.StartedAt!.Value, }) .ToListAsync(cancellationToken); @@ -438,7 +436,7 @@ await databaseContextFactory.UseContext( { var totalSpan = TimeSpan.Zero; foreach (var previousCompileJob in previousCompileJobs) - totalSpan += previousCompileJob.StoppedAt.Value - previousCompileJob.StartedAt.Value; + totalSpan += previousCompileJob.StoppedAt - previousCompileJob.StartedAt; averageSpan = totalSpan / previousCompileJobs.Count; } @@ -501,7 +499,7 @@ await remoteDeploymentManager.StartDeployment( compileJob, cancellationToken); - logger.LogTrace("Deployment will timeout at {timeoutTime}", DateTimeOffset.UtcNow + dreamMakerSettings.Timeout.Value); + logger.LogTrace("Deployment will timeout at {timeoutTime}", DateTimeOffset.UtcNow + dreamMakerSettings.Timeout!.Value); using var timeoutTokenSource = new CancellationTokenSource(dreamMakerSettings.Timeout.Value); var timeoutToken = timeoutTokenSource.Token; using (timeoutToken.Register(() => logger.LogWarning("Deployment timed out!"))) @@ -563,7 +561,7 @@ async ValueTask RunCompileJob( IRemoteDeploymentManager remoteDeploymentManager, CancellationToken cancellationToken) { - var outputDirectory = job.DirectoryName.ToString(); + var outputDirectory = job.DirectoryName!.Value.ToString(); logger.LogTrace("Compile output GUID: {dirGuid}", outputDirectory); try @@ -647,13 +645,13 @@ await eventConsumer.HandleEvent( progressReporter.StageName = "Validating DMAPI"; await VerifyApi( - launchParameters.StartupTimeout.Value, - dreamMakerSettings.ApiValidationSecurityLevel.Value, + launchParameters.StartupTimeout!.Value, + dreamMakerSettings.ApiValidationSecurityLevel!.Value, job, engineLock, - dreamMakerSettings.ApiValidationPort.Value, - dreamMakerSettings.RequireDMApiValidation.Value, - launchParameters.LogOutput.Value, + dreamMakerSettings.ApiValidationPort!.Value, + dreamMakerSettings.RequireDMApiValidation!.Value, + launchParameters.LogOutput!.Value, cancellationToken); } catch (JobException) @@ -799,7 +797,7 @@ async ValueTask VerifyApi( ApiValidationStatus validationStatus; await using (var provider = new TemporaryDmbProvider( - ioManager.ResolvePath(job.DirectoryName.ToString()), + ioManager.ResolvePath(job.DirectoryName!.Value.ToString()), job, engineLock.Version)) await using (var controller = await sessionControllerFactory.LaunchNew(provider, engineLock, launchParameters, true, cancellationToken)) @@ -859,7 +857,7 @@ async ValueTask RunDreamMaker(IEngineExecutableLock engineLock, Models.Com await using var dm = processExecutor.LaunchProcess( engineLock.CompilerExePath, ioManager.ResolvePath( - job.DirectoryName.ToString()), + job.DirectoryName!.Value.ToString()), arguments, readStandardHandles: true, noShellExecute: true); @@ -889,14 +887,15 @@ async ValueTask RunDreamMaker(IEngineExecutableLock engineLock, Models.Com async ValueTask ModifyDme(Models.CompileJob job, CancellationToken cancellationToken) { var dmeFileName = String.Join('.', job.DmeName, DmeExtension); - var dmePath = ioManager.ConcatPath(job.DirectoryName.ToString(), dmeFileName); + var stringDirectoryName = job.DirectoryName!.Value.ToString(); + var dmePath = ioManager.ConcatPath(stringDirectoryName, dmeFileName); var dmeReadTask = ioManager.ReadAllBytes(dmePath, cancellationToken); var dmeModificationsTask = configuration.CopyDMFilesTo( dmeFileName, ioManager.ResolvePath( ioManager.ConcatPath( - job.DirectoryName.ToString(), + stringDirectoryName, ioManager.GetDirectoryName(dmeFileName))), cancellationToken); @@ -955,7 +954,7 @@ ValueTask CleanupFailedCompile(Models.CompileJob job, IRemoteDeploymentManager r async ValueTask CleanDir() { logger.LogTrace("Cleaning compile directory..."); - var jobPath = job.DirectoryName.ToString(); + var jobPath = job.DirectoryName!.Value.ToString(); try { // DCT: None available diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs index a2aea1401c3..0f8c86732f9 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/BaseRemoteDeploymentManager.cs @@ -52,13 +52,18 @@ protected BaseRemoteDeploymentManager( /// public async ValueTask PostDeploymentComments( CompileJob compileJob, - RevisionInformation previousRevisionInformation, + RevisionInformation? previousRevisionInformation, RepositorySettings repositorySettings, - string repoOwner, - string repoName, + string? repoOwner, + string? repoName, CancellationToken cancellationToken) { - if (repositorySettings?.AccessToken == null) + ArgumentNullException.ThrowIfNull(compileJob); + ArgumentNullException.ThrowIfNull(repositorySettings); + ArgumentNullException.ThrowIfNull(repoOwner); + ArgumentNullException.ThrowIfNull(repoName); + + if (repositorySettings.AccessToken == null) return; var deployedRevisionInformation = compileJob.RevisionInformation; diff --git a/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManager.cs b/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManager.cs index e73f6a1063c..d8017a6686c 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManager.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/Remote/IRemoteDeploymentManager.cs @@ -66,7 +66,7 @@ ValueTask StageDeployment( /// Post deployment comments to the test merge ticket. /// /// The deployed . - /// The of the previous deployment. + /// The optional of the previous deployment. /// The . /// The remote repostiory owner. /// The remote repostiory name. @@ -74,10 +74,10 @@ ValueTask StageDeployment( /// A representing the running operation. ValueTask PostDeploymentComments( CompileJob compileJob, - RevisionInformation previousRevisionInformation, + RevisionInformation? previousRevisionInformation, RepositorySettings repositorySettings, - string repoOwner, - string repoName, + string? repoOwner, + string? repoName, CancellationToken cancellationToken); /// From 84294a7069d9004a78500caa8165098faa8db8a9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 10:19:53 -0500 Subject: [PATCH 615/717] Nullify `HardLinkDmbProvider` --- .../Components/Deployment/HardLinkDmbProvider.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/HardLinkDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/HardLinkDmbProvider.cs index 99fd9c4bc26..98a8361e342 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/HardLinkDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/HardLinkDmbProvider.cs @@ -15,8 +15,6 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// @@ -155,7 +153,7 @@ async Task MirrorSourceDirectory(int? taskThrottle, CancellationToken ca if (taskThrottle.HasValue && taskThrottle < 1) throw new ArgumentOutOfRangeException(nameof(taskThrottle), taskThrottle, "taskThrottle must be at least 1!"); - var src = IOManager.ResolvePath(CompileJob.DirectoryName.ToString()); + var src = IOManager.ResolvePath(CompileJob.DirectoryName!.Value.ToString()); var dest = IOManager.ResolvePath(mirrorGuid.ToString()); using var semaphore = taskThrottle.HasValue ? new SemaphoreSlim(taskThrottle.Value) : null; @@ -180,10 +178,10 @@ async Task MirrorSourceDirectory(int? taskThrottle, CancellationToken ca /// The for the operation. /// A of s representing the running operations. The first returned is always the necessary call to . /// I genuinely don't know how this will work with symlinked files. Waiting for the issue report I guess. - IEnumerable MirrorDirectoryImpl(string src, string dest, SemaphoreSlim semaphore, CancellationToken cancellationToken) + IEnumerable MirrorDirectoryImpl(string src, string dest, SemaphoreSlim? semaphore, CancellationToken cancellationToken) { var dir = new DirectoryInfo(src); - Task subdirCreationTask = null; + Task? subdirCreationTask = null; var dreamDaemonWillAcceptOutOfDirectorySymlinks = CompileJob.MinimumSecurityLevel == DreamDaemonSecurity.Trusted; foreach (var subDirectory in dir.EnumerateDirectories()) { @@ -193,7 +191,8 @@ IEnumerable MirrorDirectoryImpl(string src, string dest, SemaphoreSlim sem if (subDirectory.Attributes.HasFlag(FileAttributes.ReparsePoint)) if (dreamDaemonWillAcceptOutOfDirectorySymlinks) { - var target = subDirectory.ResolveLinkTarget(false); + var target = subDirectory.ResolveLinkTarget(false) + ?? throw new InvalidOperationException($"\"{subDirectory.FullName}\" was incorrectly identified as a symlinked directory!"); logger.LogDebug("Recreating directory {name} as symlink to {target}", subDirectory.Name, target); if (subdirCreationTask == null) { @@ -252,7 +251,9 @@ async Task LinkThisFile() if (fileInfo.Attributes.HasFlag(FileAttributes.ReparsePoint)) { // AHHHHHHHHHHHHH - var target = fileInfo.ResolveLinkTarget(!dreamDaemonWillAcceptOutOfDirectorySymlinks); + var target = fileInfo.ResolveLinkTarget(!dreamDaemonWillAcceptOutOfDirectorySymlinks) + ?? throw new InvalidOperationException($"\"{fileInfo.FullName}\" was incorrectly identified as a symlinked file!"); + if (dreamDaemonWillAcceptOutOfDirectorySymlinks) { logger.LogDebug("Recreating symlinked file {name} as symlink to {target}", fileInfo.Name, target.FullName); From 1a4c22987a95e0cafeae1bf4a7b208c8f19c37af Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 10:20:42 -0500 Subject: [PATCH 616/717] Nullify `SwappableDmbProvider` --- .../Components/Deployment/SwappableDmbProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs index 954fa920bec..75c5a1b6bb1 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// From 5b2ce9e57edccba4ef5690b8beec8f0b87e59b37 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 10:21:03 -0500 Subject: [PATCH 617/717] Nullify `SymlinkDmbProvider` --- .../Components/Deployment/SymlinkDmbProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/SymlinkDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/SymlinkDmbProvider.cs index a920641d0d1..edb570bcb85 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/SymlinkDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/SymlinkDmbProvider.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// From ee88f8d32e89e0efc443e5f63641fd176d1a9cd9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 10:21:19 -0500 Subject: [PATCH 618/717] Nullify `TemporaryDmbProvider` --- .../Components/Deployment/TemporaryDmbProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs index 38c5067c554..4d528d7ba1e 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/TemporaryDmbProvider.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Api.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Deployment { /// From ed5d16d96e0c35686d5a5301b484d5d46e46ab95 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 15:43:31 -0500 Subject: [PATCH 619/717] Nullify `ByondInstallation` --- .../Components/Engine/ByondInstallation.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs index b1cc0a9d5dd..575d55975ce 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Components.Deployment; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// @@ -94,8 +92,8 @@ public ByondInstallation( InstallationTask = installationTask ?? throw new ArgumentNullException(nameof(installationTask)); ArgumentNullException.ThrowIfNull(version); - if (version.Engine.Value != EngineType.Byond) - throw new ArgumentException($"Invalid EngineType: {version.Engine.Value}", nameof(version)); + if (version.Engine != EngineType.Byond) + throw new ArgumentException($"Invalid EngineType: {version.Engine}", nameof(version)); Version = version ?? throw new ArgumentNullException(nameof(version)); ServerExePath = dreamDaemonPath ?? throw new ArgumentNullException(nameof(dreamDaemonPath)); @@ -122,19 +120,19 @@ public override string FormatServerArguments( CultureInfo.InvariantCulture, "{0} -port {1} -ports 1-65535 {2}-close -verbose -{3} -{4}{5}{6}{7} -params \"{8}\"", dmbProvider.DmbName, - launchParameters.Port.Value, - launchParameters.AllowWebClient.Value + launchParameters.Port!.Value, + launchParameters.AllowWebClient!.Value ? "-webclient " : String.Empty, - SecurityWord(launchParameters.SecurityLevel.Value), - VisibilityWord(launchParameters.Visibility.Value), + SecurityWord(launchParameters.SecurityLevel!.Value), + VisibilityWord(launchParameters.Visibility!.Value), logFilePath != null ? $" -logself -log {logFilePath}" : String.Empty, // DD doesn't output anything if -logself is set??? - launchParameters.StartProfiler.Value + launchParameters.StartProfiler!.Value ? " -profile" : String.Empty, - supportsMapThreads && launchParameters.MapThreads.Value != 0 + supportsMapThreads && launchParameters.MapThreads!.Value != 0 ? $" -map-threads {launchParameters.MapThreads.Value}" : String.Empty, parametersString); From 1528a3d28df3ff2b2d2a59aac539cae0b95241ad Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 15:34:26 -0500 Subject: [PATCH 620/717] Add the `DisposeInvoker` util class Closes #1730 --- .../Components/Chat/ChatTrackingContext.cs | 44 +++++------------ .../Components/Deployment/DmbFactory.cs | 5 +- .../Components/Deployment/DmbProvider.cs | 7 +-- .../Interop/Bridge/BridgeRegistration.cs | 31 +++--------- .../Components/Repository/Repository.cs | 43 +++++----------- .../Core/RestartRegistration.cs | 14 +++--- src/Tgstation.Server.Host/Server.cs | 14 +++--- .../Utils/DisposeInvoker.cs | 49 +++++++++++++++++++ 8 files changed, 103 insertions(+), 104 deletions(-) create mode 100644 src/Tgstation.Server.Host/Utils/DisposeInvoker.cs diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs b/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs index 1f3d196bcd1..02b6675323f 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatTrackingContext.cs @@ -7,16 +7,17 @@ using Microsoft.Extensions.Logging; using Tgstation.Server.Host.Components.Chat.Commands; +using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.Components.Chat { /// - sealed class ChatTrackingContext : IChatTrackingContext + sealed class ChatTrackingContext : DisposeInvoker, IChatTrackingContext { /// public bool Active { - get => active && onDispose != null; + get => active && !IsDisposed; set { if (active == value) @@ -61,24 +62,19 @@ public IEnumerable CustomCommands readonly ILogger logger; /// - /// for modifying , , and . + /// for modifying and calling . /// readonly object synchronizationLock; - /// - /// Backing field for . - /// - IReadOnlyCollection customCommands; - /// /// The if any. /// - IChannelSink? channelSink; + volatile IChannelSink? channelSink; /// - /// The to run when d. + /// Backing field for . /// - Action? onDispose; + IReadOnlyCollection customCommands; /// /// Backing field for . @@ -91,45 +87,31 @@ public IEnumerable CustomCommands /// The value of . /// The initial value of . /// The value of . - /// The value of . + /// The action for the . public ChatTrackingContext( ICustomCommandHandler customCommandHandler, IEnumerable initialChannels, ILogger logger, - Action onDispose) + Action disposeAction) + : base(disposeAction) { this.customCommandHandler = customCommandHandler ?? throw new ArgumentNullException(nameof(customCommandHandler)); Channels = initialChannels?.ToList() ?? throw new ArgumentNullException(nameof(initialChannels)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.onDispose = onDispose ?? throw new ArgumentNullException(nameof(onDispose)); synchronizationLock = new object(); Active = true; customCommands = Array.Empty(); } - /// - public void Dispose() - { - lock (synchronizationLock) - { - onDispose?.Invoke(); - onDispose = null; - } - } - /// public void SetChannelSink(IChannelSink channelSink) { ArgumentNullException.ThrowIfNull(channelSink); - lock (synchronizationLock) - { - if (this.channelSink != null) - throw new InvalidOperationException("channelSink already set!"); - - this.channelSink = channelSink; - } + var originalValue = Interlocked.CompareExchange(ref this.channelSink, channelSink, null); + if (originalValue != null) + throw new InvalidOperationException("channelSink already set!"); } /// diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs index 0c5c43d31ee..3b6695313b5 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs @@ -16,6 +16,7 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Models; +using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.Components.Deployment { @@ -279,7 +280,7 @@ void CleanupAction() CleanRegisteredCompileJob(compileJob); } - var newProvider = new DmbProvider(compileJob, engineVersion, ioManager, CleanupAction); + var newProvider = new DmbProvider(compileJob, engineVersion, ioManager, new DisposeInvoker(CleanupAction)); try { const string LegacyADirectoryName = "A"; @@ -316,7 +317,7 @@ void CleanupAction() // rebuild the provider because it's using the legacy style directories // Don't dispose it logger.LogDebug("Creating legacy two folder .dmb provider targeting {aDirName} directory...", LegacyADirectoryName); - newProvider = new DmbProvider(compileJob, engineVersion, ioManager, CleanupAction, Path.DirectorySeparatorChar + LegacyADirectoryName); + newProvider = new DmbProvider(compileJob, engineVersion, ioManager, new DisposeInvoker(CleanupAction), Path.DirectorySeparatorChar + LegacyADirectoryName); } lock (jobLockCounts) diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs index 4a21e4e8d2c..be47aeb6b3c 100644 --- a/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs +++ b/src/Tgstation.Server.Host/Components/Deployment/DmbProvider.cs @@ -4,6 +4,7 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.IO; +using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.Components.Deployment { @@ -32,7 +33,7 @@ sealed class DmbProvider : DmbProviderBase, IDmbProvider /// /// The to run when is called. /// - Action? onDispose; + DisposeInvoker? onDispose; /// /// Initializes a new instance of the class. @@ -42,7 +43,7 @@ sealed class DmbProvider : DmbProviderBase, IDmbProvider /// The value of . /// The value of . /// The optional value of . - public DmbProvider(Models.CompileJob compileJob, EngineVersion engineVersion, IIOManager ioManager, Action onDispose, string? directoryAppend = null) + public DmbProvider(Models.CompileJob compileJob, EngineVersion engineVersion, IIOManager ioManager, DisposeInvoker onDispose, string? directoryAppend = null) { CompileJob = compileJob ?? throw new ArgumentNullException(nameof(compileJob)); EngineVersion = engineVersion ?? throw new ArgumentNullException(nameof(engineVersion)); @@ -54,7 +55,7 @@ public DmbProvider(Models.CompileJob compileJob, EngineVersion engineVersion, II /// public override ValueTask DisposeAsync() { - onDispose?.Invoke(); + onDispose?.Dispose(); return ValueTask.CompletedTask; } diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeRegistration.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeRegistration.cs index e209a63aa6a..38acfd827d3 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeRegistration.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeRegistration.cs @@ -1,40 +1,21 @@ using System; +using Tgstation.Server.Host.Utils; + #nullable disable namespace Tgstation.Server.Host.Components.Interop.Bridge { /// - sealed class BridgeRegistration : IBridgeRegistration + sealed class BridgeRegistration : DisposeInvoker, IBridgeRegistration { - /// - /// for accessing . - /// - readonly object lockObject; - - /// - /// to run when d. - /// - Action onDispose; - /// /// Initializes a new instance of the class. /// - /// The value of . - public BridgeRegistration(Action onDispose) - { - this.onDispose = onDispose ?? throw new ArgumentNullException(nameof(onDispose)); - lockObject = new object(); - } - - /// - public void Dispose() + /// The action for the . + public BridgeRegistration(Action disposeAction) + : base(disposeAction) { - lock (lockObject) - { - onDispose?.Invoke(); - onDispose = null; - } } } } diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs index 6ef027416e3..c083dfdde6b 100644 --- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs @@ -17,6 +17,7 @@ using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; +using Tgstation.Server.Host.Utils; #nullable disable @@ -24,7 +25,7 @@ namespace Tgstation.Server.Host.Components.Repository { /// #pragma warning disable CA1506 // TODO: Decomplexify - sealed class Repository : IRepository + sealed class Repository : DisposeInvoker, IRepository { /// /// The default username for committers. @@ -117,16 +118,6 @@ sealed class Repository : IRepository /// readonly GeneralConfiguration generalConfiguration; - /// - /// to be taken when is called. - /// - readonly Action onDispose; - - /// - /// If the was disposed. - /// - bool disposed; - /// /// Initializes a new instance of the class. /// @@ -139,7 +130,7 @@ sealed class Repository : IRepository /// The to provide the value of . /// The value of . /// The value of . - /// The value if . + /// The action for the . public Repository( LibGit2Sharp.IRepository libGitRepo, ILibGit2Commands commands, @@ -150,7 +141,8 @@ public Repository( IGitRemoteFeaturesFactory gitRemoteFeaturesFactory, ILogger logger, GeneralConfiguration generalConfiguration, - Action onDispose) + Action disposeAction) + : base(disposeAction) { this.libGitRepo = libGitRepo ?? throw new ArgumentNullException(nameof(libGitRepo)); this.commands = commands ?? throw new ArgumentNullException(nameof(commands)); @@ -162,27 +154,10 @@ public Repository( this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.generalConfiguration = generalConfiguration ?? throw new ArgumentNullException(nameof(generalConfiguration)); - this.onDispose = onDispose ?? throw new ArgumentNullException(nameof(onDispose)); gitRemoteFeatures = gitRemoteFeaturesFactory.CreateGitRemoteFeatures(this); } - /// - public void Dispose() - { - lock (onDispose) - { - if (disposed) - return; - - disposed = true; - } - - logger.LogTrace("Disposing..."); - libGitRepo.Dispose(); - onDispose(); - } - /// #pragma warning disable CA1506 // TODO: Decomplexify public async ValueTask AddTestMerge( @@ -869,6 +844,14 @@ public Task TimestampCommit(string sha, CancellationToken cancel DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current); + /// + protected override void DisposeImpl() + { + logger.LogTrace("Disposing..."); + libGitRepo.Dispose(); + base.DisposeImpl(); + } + /// /// Runs a blocking force checkout to . /// diff --git a/src/Tgstation.Server.Host/Core/RestartRegistration.cs b/src/Tgstation.Server.Host/Core/RestartRegistration.cs index 8f4ab937d6b..2cd24e307de 100644 --- a/src/Tgstation.Server.Host/Core/RestartRegistration.cs +++ b/src/Tgstation.Server.Host/Core/RestartRegistration.cs @@ -1,4 +1,4 @@ -using System; +using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.Core { @@ -6,20 +6,20 @@ namespace Tgstation.Server.Host.Core sealed class RestartRegistration : IRestartRegistration { /// - /// The . + /// The . /// - readonly Action? onDispose; + readonly DisposeInvoker? disposeInvoker; /// /// Initializes a new instance of the class. /// - /// The value of . - public RestartRegistration(Action? onDispose) + /// The value of . + public RestartRegistration(DisposeInvoker? disposeInvoker) { - this.onDispose = onDispose; + this.disposeInvoker = disposeInvoker; } /// - public void Dispose() => onDispose?.Invoke(); + public void Dispose() => disposeInvoker?.Dispose(); } } diff --git a/src/Tgstation.Server.Host/Server.cs b/src/Tgstation.Server.Host/Server.cs index b832be6e873..751cd2d453d 100644 --- a/src/Tgstation.Server.Host/Server.cs +++ b/src/Tgstation.Server.Host/Server.cs @@ -13,6 +13,7 @@ using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Core; +using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host { @@ -234,12 +235,13 @@ public IRestartRegistration RegisterForRestart(IRestartHandler handler) { logger.LogTrace("Registering restart handler {handlerImplementationName}...", handler); restartHandlers.Add(handler); - return new RestartRegistration(() => - { - lock (restartLock) - if (!shutdownInProgress) - restartHandlers.Remove(handler); - }); + return new RestartRegistration( + new DisposeInvoker(() => + { + lock (restartLock) + if (!shutdownInProgress) + restartHandlers.Remove(handler); + })); } logger.LogWarning("Restart handler {handlerImplementationName} register after a shutdown had begun!", handler); diff --git a/src/Tgstation.Server.Host/Utils/DisposeInvoker.cs b/src/Tgstation.Server.Host/Utils/DisposeInvoker.cs new file mode 100644 index 00000000000..b90d01318b7 --- /dev/null +++ b/src/Tgstation.Server.Host/Utils/DisposeInvoker.cs @@ -0,0 +1,49 @@ +using System; +using System.Threading; + +namespace Tgstation.Server.Host.Utils +{ + /// + /// Runs a given on . + /// + class DisposeInvoker : IDisposable + { + /// + /// If was called. + /// + public bool IsDisposed => disposeRan != 0; + + /// + /// The to run on . + /// + readonly Action disposeAction; + + /// + /// An representation of a indicating if has ran. + /// + volatile int disposeRan; + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + public DisposeInvoker(Action disposeAction) + { + this.disposeAction = disposeAction ?? throw new ArgumentNullException(nameof(disposeAction)); + } + + /// + public void Dispose() + { + if (Interlocked.Exchange(ref disposeRan, 1) != 0) + return; + + DisposeImpl(); + } + + /// + /// Implementation of run after reentrancy check. + /// + protected virtual void DisposeImpl() => disposeAction(); + } +} From 594b4fc42a8587eca13cea98e74e3e629cee63db Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 18:16:55 -0500 Subject: [PATCH 621/717] Nullify `ByondInstallerBase` --- .../Components/Engine/ByondInstallerBase.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index 7aef964b9c0..28ac0990bcd 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -11,8 +11,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// @@ -100,7 +98,7 @@ public override IEngineInstallation CreateInstallation(EngineVersion version, st IOManager.ConcatPath( binPathForVersion, GetDreamDaemonName( - version.Version, + version.Version!, out var supportsCli))), IOManager.ResolvePath( IOManager.ConcatPath( @@ -237,7 +235,7 @@ public override async ValueTask DownloadVersion(EngineV Uri GetDownloadZipUrl(EngineVersion version) { CheckVersionValidity(version); - var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Version.Major, version.Version.Minor); + var url = String.Format(CultureInfo.InvariantCulture, ByondRevisionsUrlTemplate, version.Version!.Major, version.Version.Minor); return new Uri(url); } } From 9ef9bf325ab1885151d4a21b2050410433386c3f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 18:17:39 -0500 Subject: [PATCH 622/717] Nullify `DelegatingEngineInstaller` --- .../Components/Engine/DelegatingEngineInstaller.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs index c9e859f37de..1c68bf1dc2a 100644 --- a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Jobs; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// @@ -64,7 +62,7 @@ public ValueTask UpgradeInstallation(EngineVersion version, string path, Cancell TReturn DelegateCall(EngineVersion version, Func call) { ArgumentNullException.ThrowIfNull(version); - return call(delegatedInstallers[version.Engine.Value]); + return call(delegatedInstallers[version.Engine!.Value]); } } } From f23d21e7edba36fd61fbf8e5e8e6d0413dda5a1b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 18:22:17 -0500 Subject: [PATCH 623/717] Nullify `EngineExecutableLock` --- .../Components/Engine/EngineExecutableLock.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs index 36944a876fb..af04f89224a 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// From dec95b8eb9a533dbcd766307fe87bcffa0f4e91a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 18:26:00 -0500 Subject: [PATCH 624/717] Nullify `EngineInstallationBase` --- .../Components/Engine/EngineInstallationBase.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs index bbf809ee253..24438606233 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs @@ -12,8 +12,6 @@ using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// From b27be9426d5c9bb62db2afae02a4b534440822fe Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 18:32:33 -0500 Subject: [PATCH 625/717] Nullify `EngineInstallerBase` --- .../Components/Engine/EngineInstallerBase.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs index 6e2d5ad3cc9..1993c55f1bd 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs @@ -8,8 +8,6 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// @@ -66,7 +64,7 @@ protected EngineInstallerBase(IIOManager ioManager, ILogger protected void CheckVersionValidity(EngineVersion version) { ArgumentNullException.ThrowIfNull(version); - if (version.Engine.Value != TargetEngineType) + if (version.Engine!.Value != TargetEngineType) throw new InvalidOperationException($"Non-{TargetEngineType} engine specified: {version.Engine.Value}"); } } From 05f8278f4a6d8ad7c886cbd4acf68333b82cc1af Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 19:40:58 -0500 Subject: [PATCH 626/717] Nullify `EngineManager` and `IEngineManager` Fix a potential `NullReferenceException` with no `JobProgressReporter` --- .../Components/Chat/Commands/EngineCommand.cs | 2 +- .../Components/Engine/EngineManager.cs | 47 +++++++++++-------- .../Components/Engine/IEngineManager.cs | 12 ++--- .../Components/Events/EventConsumer.cs | 2 +- .../Components/Events/IEventConsumer.cs | 2 +- .../Components/Events/NoopEventConsumer.cs | 2 +- .../Components/StaticFiles/Configuration.cs | 5 +- .../Controllers/EngineController.cs | 4 +- 8 files changed, 42 insertions(+), 34 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs index 21789bb2586..c0bf80ea594 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Commands/EngineCommand.cs @@ -48,7 +48,7 @@ public EngineCommand(IEngineManager engineManager, IWatchdog watchdog) /// public ValueTask Invoke(string arguments, ChatUser user, CancellationToken cancellationToken) { - EngineVersion engineVersion; + EngineVersion? engineVersion; if (arguments.Split(' ').Any(x => x.Equals("--active", StringComparison.OrdinalIgnoreCase))) engineVersion = engineManager.ActiveVersion; else diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs index ab767631672..529eec0fb8e 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineManager.cs @@ -16,8 +16,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// @@ -34,7 +32,7 @@ sealed class EngineManager : IEngineManager const string ActiveVersionFileName = "ActiveVersion.txt"; /// - public EngineVersion ActiveVersion { get; private set; } + public EngineVersion? ActiveVersion { get; private set; } /// public IReadOnlyList InstalledVersions @@ -120,9 +118,9 @@ public EngineManager(IIOManager ioManager, IEngineInstaller engineInstaller, IEv /// public async ValueTask ChangeVersion( - JobProgressReporter progressReporter, + JobProgressReporter? progressReporter, EngineVersion version, - Stream customVersionStream, + Stream? customVersionStream, bool allowInstallation, CancellationToken cancellationToken) { @@ -145,7 +143,7 @@ public async ValueTask ChangeVersion( await ioManager.WriteAllBytes(ActiveVersionFileName, Encoding.UTF8.GetBytes(stringVersion), cancellationToken); await eventConsumer.HandleEvent( EventType.EngineActiveVersionChange, - new List + new List { ActiveVersion?.ToString(), stringVersion, @@ -162,7 +160,7 @@ await eventConsumer.HandleEvent( } /// - public async ValueTask UseExecutables(EngineVersion requiredVersion, string trustDmbFullPath, CancellationToken cancellationToken) + public async ValueTask UseExecutables(EngineVersion? requiredVersion, string? trustDmbFullPath, CancellationToken cancellationToken) { logger.LogTrace( "Acquiring lock on BYOND version {version}...", @@ -198,19 +196,21 @@ public async ValueTask DeleteVersion(JobProgressReporter progressReporter, Engin logger.LogTrace("DeleteVersion {version}", version); - if (version.Equals(ActiveVersion)) + var activeVersion = ActiveVersion; + if (activeVersion != null && version.Equals(activeVersion)) throw new JobException(ErrorCode.EngineCannotDeleteActiveVersion); ReferenceCountingContainer container; logger.LogTrace("Waiting to acquire installedVersions lock..."); lock (installedVersions) { - if (!installedVersions.TryGetValue(version, out container)) + if (!installedVersions.TryGetValue(version, out var containerNullable)) { logger.LogTrace("Version {version} already deleted.", version); return; } + container = containerNullable; logger.LogTrace("Installation container acquired for deletion"); } @@ -238,7 +238,8 @@ await Task.WhenAny( using (await SemaphoreSlimContext.Lock(changeDeleteSemaphore, cancellationToken)) { // check again because it could have become the active version. - if (version.Equals(ActiveVersion)) + activeVersion = ActiveVersion; + if (activeVersion != null && version.Equals(activeVersion)) throw new JobException(ErrorCode.EngineCannotDeleteActiveVersion); bool proceed; @@ -296,7 +297,7 @@ await ioManager.DeleteFile( /// public async Task StartAsync(CancellationToken cancellationToken) { - async ValueTask GetActiveVersion() + async ValueTask GetActiveVersion() { var activeVersionFileExists = await ioManager.FileExists(ActiveVersionFileName, cancellationToken); return !activeVersionFileExists ? null : await ioManager.ReadAllBytes(ActiveVersionFileName, cancellationToken); @@ -321,12 +322,15 @@ async ValueTask ReadVersion(string path) var bytes = await ioManager.ReadAllBytes(versionFile, cancellationToken); var text = Encoding.UTF8.GetString(bytes); - if (!EngineVersion.TryParse(text, out var version)) + EngineVersion version; + if (!EngineVersion.TryParse(text, out var versionNullable)) { logger.LogWarning("Cleaning path with unparsable version file: {versionPath}", ioManager.ResolvePath(path)); await ioManager.DeleteDirectory(path, cancellationToken); // cleanup return; } + else + version = versionNullable!; try { @@ -362,11 +366,11 @@ await ValueTaskExtensions.WhenAll( { var activeVersionString = Encoding.UTF8.GetString(activeVersionBytes); - EngineVersion activeVersion; + EngineVersion? activeVersion; bool hasRequestedActiveVersion; lock (installedVersions) hasRequestedActiveVersion = EngineVersion.TryParse(activeVersionString, out activeVersion) - && installedVersions.ContainsKey(activeVersion); + && installedVersions.ContainsKey(activeVersion!); if (hasRequestedActiveVersion) ActiveVersion = activeVersion; // not setting TCS because there's no need during init @@ -386,15 +390,15 @@ await ValueTaskExtensions.WhenAll( /// /// The optional for the operation. /// The to install. - /// Custom zip file to use. Will cause a number to be added. + /// Optional custom zip file to use. Will cause a number to be added. /// If this BYOND version is required as part of a locking operation. /// If an installation should be performed if the is not installed. If and an installation is required an will be thrown. /// The for the operation. /// A resulting in the . async ValueTask AssertAndLockVersion( - JobProgressReporter progressReporter, + JobProgressReporter? progressReporter, EngineVersion version, - Stream customVersionStream, + Stream? customVersionStream, bool neededForLock, bool allowInstallation, CancellationToken cancellationToken) @@ -415,7 +419,8 @@ async ValueTask AssertAndLockVersion( while (installedVersions.ContainsKey(version)); } - installedOrInstalling = installedVersions.TryGetValue(version, out var installationContainer); + installedOrInstalling = installedVersions.TryGetValue(version, out var installationContainerNullable); + ReferenceCountingContainer installationContainer; if (!installedOrInstalling) { if (!allowInstallation) @@ -426,6 +431,8 @@ async ValueTask AssertAndLockVersion( ioManager.ResolvePath(version.ToString()), ourTcs.Task); } + else + installationContainer = installationContainerNullable!; installation = installationContainer.Instance; installLock = installationContainer.AddReference(); @@ -499,7 +506,7 @@ async ValueTask AssertAndLockVersion( /// Custom zip file to use. Will cause a number to be added. /// The for the operation. /// A representing the running operation. - async ValueTask InstallVersionFiles(JobProgressReporter progressReporter, EngineVersion version, Stream customVersionStream, CancellationToken cancellationToken) + async ValueTask InstallVersionFiles(JobProgressReporter? progressReporter, EngineVersion version, Stream? customVersionStream, CancellationToken cancellationToken) { var installFullPath = ioManager.ResolvePath(version.ToString()); async ValueTask DirectoryCleanup() @@ -519,7 +526,7 @@ async ValueTask DirectoryCleanup() engineInstallationData = await engineInstaller.DownloadVersion(version, progressReporter, cancellationToken); - progressReporter.ReportProgress(null); + progressReporter?.ReportProgress(null); } else #pragma warning disable CA2000 // Dispose objects before losing scope, false positive diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs index d53d77c53ab..18af1469e6d 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineManager.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Jobs; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// @@ -20,7 +18,7 @@ public interface IEngineManager : IComponentService, IDisposable /// /// The currently active . /// - EngineVersion ActiveVersion { get; } + EngineVersion? ActiveVersion { get; } /// /// The installed s. @@ -37,9 +35,9 @@ public interface IEngineManager : IComponentService, IDisposable /// The for the operation. /// A representing the running operation. ValueTask ChangeVersion( - JobProgressReporter progressReporter, + JobProgressReporter? progressReporter, EngineVersion version, - Stream customVersionStream, + Stream? customVersionStream, bool allowInstallation, CancellationToken cancellationToken); @@ -60,8 +58,8 @@ ValueTask ChangeVersion( /// The for the operation. /// A resulting in the requested . ValueTask UseExecutables( - EngineVersion requiredVersion, - string trustDmbFullPath, + EngineVersion? requiredVersion, + string? trustDmbFullPath, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs index 8cc073ccda2..6c8b6811281 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs @@ -31,7 +31,7 @@ public EventConsumer(IConfiguration configuration) } /// - public async ValueTask HandleEvent(EventType eventType, IEnumerable parameters, bool deploymentPipeline, CancellationToken cancellationToken) + public async ValueTask HandleEvent(EventType eventType, IEnumerable parameters, bool deploymentPipeline, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(parameters); diff --git a/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs index 7fddbb8950f..4d268011f12 100644 --- a/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs +++ b/src/Tgstation.Server.Host/Components/Events/IEventConsumer.cs @@ -17,6 +17,6 @@ public interface IEventConsumer /// If this event is part of the deployment pipeline. /// The for the operation. /// A representing the running operation. - ValueTask HandleEvent(EventType eventType, IEnumerable parameters, bool deploymentPipeline, CancellationToken cancellationToken); + ValueTask HandleEvent(EventType eventType, IEnumerable parameters, bool deploymentPipeline, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs index a8b07e4d7e0..dde777572ad 100644 --- a/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs +++ b/src/Tgstation.Server.Host/Components/Events/NoopEventConsumer.cs @@ -10,7 +10,7 @@ namespace Tgstation.Server.Host.Components.Events sealed class NoopEventConsumer : IEventConsumer { /// - public ValueTask HandleEvent(EventType eventType, IEnumerable parameters, bool deploymentPipeline, CancellationToken cancellationToken) + public ValueTask HandleEvent(EventType eventType, IEnumerable parameters, bool deploymentPipeline, CancellationToken cancellationToken) => ValueTask.CompletedTask; } } diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs index b2e12d19473..8261afe9181 100644 --- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs +++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs @@ -600,7 +600,7 @@ void WriteCallback() public Task StopAsync(CancellationToken cancellationToken) => EnsureDirectories(cancellationToken); /// - public async ValueTask HandleEvent(EventType eventType, IEnumerable parameters, bool deploymentPipeline, CancellationToken cancellationToken) + public async ValueTask HandleEvent(EventType eventType, IEnumerable parameters, bool deploymentPipeline, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(parameters); @@ -637,6 +637,9 @@ public async ValueTask HandleEvent(EventType eventType, IEnumerable para ' ', parameters.Select(arg => { + if (arg == null) + return "(NULL)"; + if (!arg.Contains(' ', StringComparison.Ordinal)) return arg; diff --git a/src/Tgstation.Server.Host/Controllers/EngineController.cs b/src/Tgstation.Server.Host/Controllers/EngineController.cs index d5072c597f3..c1a20fe99ca 100644 --- a/src/Tgstation.Server.Host/Controllers/EngineController.cs +++ b/src/Tgstation.Server.Host/Controllers/EngineController.cs @@ -296,8 +296,8 @@ public async ValueTask Delete([FromBody] EngineVersionDeleteReque instance => { var byondManager = instance.EngineManager; - - if (engineVersion.Equals(byondManager.ActiveVersion)) + var activeVersion = byondManager.ActiveVersion; + if (activeVersion != null && engineVersion.Equals(activeVersion)) return ValueTask.FromResult( Conflict(new ErrorMessageResponse(ErrorCode.EngineCannotDeleteActiveVersion))); From 9ebfbebf15a2b627cc369ecb3871546c3c254856 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 19:41:23 -0500 Subject: [PATCH 627/717] Nullify `IEngineExecutableLock` --- .../Components/Engine/IEngineExecutableLock.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineExecutableLock.cs index 5d7bb087f96..66031902fbb 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineExecutableLock.cs @@ -1,7 +1,5 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// From 080859b530f217635c2039068687e9cdc649f918 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 20:41:28 -0500 Subject: [PATCH 628/717] Nullify `IEngineInstallationData` --- .../Components/Engine/IEngineInstallationData.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs index 6385be5a9ed..b3d8458973c 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallationData.cs @@ -2,8 +2,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// From 217669d262d1e463137db2dde20b7ecc0a3cca35 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 20:41:13 -0500 Subject: [PATCH 629/717] Nullify `IEngineInstallation` --- .../Components/Engine/ByondInstallation.cs | 2 +- .../Components/Engine/EngineExecutableLock.cs | 2 +- .../Components/Engine/EngineInstallationBase.cs | 2 +- .../Components/Engine/IEngineInstallation.cs | 4 +--- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs index 575d55975ce..fce9b2c5bc3 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallation.cs @@ -108,7 +108,7 @@ public override string FormatServerArguments( IDmbProvider dmbProvider, IReadOnlyDictionary parameters, DreamDaemonLaunchParameters launchParameters, - string logFilePath) + string? logFilePath) { ArgumentNullException.ThrowIfNull(dmbProvider); ArgumentNullException.ThrowIfNull(parameters); diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs index af04f89224a..5d7a1d7fef3 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineExecutableLock.cs @@ -44,7 +44,7 @@ public string FormatServerArguments( IDmbProvider dmbProvider, IReadOnlyDictionary parameters, DreamDaemonLaunchParameters launchParameters, - string logFilePath) + string? logFilePath) => Instance.FormatServerArguments( dmbProvider, parameters, diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs index 24438606233..5edf44609f0 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallationBase.cs @@ -64,7 +64,7 @@ public abstract string FormatServerArguments( IDmbProvider dmbProvider, IReadOnlyDictionary parameters, DreamDaemonLaunchParameters launchParameters, - string logFilePath); + string? logFilePath); /// public virtual async ValueTask StopServerProcess(ILogger logger, IProcess process, string accessIdentifier, ushort port, CancellationToken cancellationToken) diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs index bd7fa9e1804..ff2e4155f34 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstallation.cs @@ -9,8 +9,6 @@ using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// @@ -65,7 +63,7 @@ string FormatServerArguments( IDmbProvider dmbProvider, IReadOnlyDictionary parameters, DreamDaemonLaunchParameters launchParameters, - string logFilePath); + string? logFilePath); /// /// Return the command line arguments for compiling a given if compilation is necessary. From c922ade2d7c89c1e75f9a8529bca6a232c6da848 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 20:46:18 -0500 Subject: [PATCH 630/717] Nullify `IEngineInstaller` --- .../Components/Engine/ByondInstallerBase.cs | 2 +- .../Components/Engine/DelegatingEngineInstaller.cs | 2 +- .../Components/Engine/EngineInstallerBase.cs | 2 +- .../Components/Engine/IEngineInstaller.cs | 4 +--- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs index 28ac0990bcd..02691acfc08 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ByondInstallerBase.cs @@ -194,7 +194,7 @@ public override async ValueTask TrustDmbPath(EngineVersion version, string fullD } /// - public override async ValueTask DownloadVersion(EngineVersion version, JobProgressReporter progressReporter, CancellationToken cancellationToken) + public override async ValueTask DownloadVersion(EngineVersion version, JobProgressReporter? progressReporter, CancellationToken cancellationToken) { CheckVersionValidity(version); diff --git a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs index 1c68bf1dc2a..c7c5363a955 100644 --- a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs @@ -37,7 +37,7 @@ public IEngineInstallation CreateInstallation(EngineVersion version, string path => DelegateCall(version, installer => installer.CreateInstallation(version, path, installationTask)); /// - public ValueTask DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken) + public ValueTask DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken) => DelegateCall(version, installer => installer.DownloadVersion(version, jobProgressReporter, cancellationToken)); /// diff --git a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs index 1993c55f1bd..7c25c0a13c6 100644 --- a/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs +++ b/src/Tgstation.Server.Host/Components/Engine/EngineInstallerBase.cs @@ -52,7 +52,7 @@ protected EngineInstallerBase(IIOManager ioManager, ILogger public abstract ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken); /// - public abstract ValueTask DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken); + public abstract ValueTask DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken); /// public abstract ValueTask TrustDmbPath(EngineVersion version, string fullDmbPath, CancellationToken cancellationToken); diff --git a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs index 427ebfe55fc..7169ffe4b57 100644 --- a/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/IEngineInstaller.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Jobs; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// @@ -29,7 +27,7 @@ interface IEngineInstaller /// The optional for the operation. /// The for the operation. /// A resulting in the for the download. - ValueTask DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken); + ValueTask DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken); /// /// Does actions necessary to get an extracted installation working. From 38fe6df7dae16716c4a96237da76d7dd01ed7eb1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 20:47:46 -0500 Subject: [PATCH 631/717] Nullify `OpenDreamInstallation` --- .../Components/Engine/OpenDreamInstallation.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index c16e25c9a18..ab9eb923d84 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -19,8 +19,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// @@ -91,7 +89,7 @@ public OpenDreamInstallation( InstallationTask = installationTask ?? throw new ArgumentNullException(nameof(installationTask)); Version = version ?? throw new ArgumentNullException(nameof(version)); - if (version.Engine.Value != EngineType.OpenDream) + if (version.Engine!.Value != EngineType.OpenDream) throw new ArgumentException($"Invalid EngineType: {version.Engine.Value}", nameof(version)); } @@ -100,7 +98,7 @@ public override string FormatServerArguments( IDmbProvider dmbProvider, IReadOnlyDictionary parameters, DreamDaemonLaunchParameters launchParameters, - string logFilePath) + string? logFilePath) { ArgumentNullException.ThrowIfNull(dmbProvider); ArgumentNullException.ThrowIfNull(parameters); @@ -111,8 +109,7 @@ public override string FormatServerArguments( var parametersString = EncodeParameters(parameters, launchParameters); - var loggingEnabled = logFilePath != null; - var arguments = $"--cvar {(loggingEnabled ? $"log.path=\"{ioManager.GetDirectoryName(logFilePath)}\" --cvar log.format=\"{ioManager.GetFileName(logFilePath)}\"" : "log.enabled=false")} --cvar watchdog.token={accessIdentifier} --cvar log.runtimelog=false --cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" --cvar opendream.json_path=\"./{dmbProvider.DmbName}\""; + var arguments = $"--cvar {(logFilePath != null ? $"log.path=\"{ioManager.GetDirectoryName(logFilePath)}\" --cvar log.format=\"{ioManager.GetFileName(logFilePath)}\"" : "log.enabled=false")} --cvar watchdog.token={accessIdentifier} --cvar log.runtimelog=false --cvar net.port={launchParameters.Port!.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" --cvar opendream.json_path=\"./{dmbProvider.DmbName}\""; return arguments; } From 91dcb5cda63ed819fa2a4d293dac4863330ecab4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 20:48:59 -0500 Subject: [PATCH 632/717] Nullify `OpenDreamInstaller` --- .../Components/Engine/OpenDreamInstaller.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index c5f03e1e329..5244816ead0 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -17,8 +17,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// @@ -136,7 +134,7 @@ public override IEngineInstallation CreateInstallation(EngineVersion version, st } /// - public override async ValueTask DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken) + public override async ValueTask DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken) { CheckVersionValidity(version); @@ -172,7 +170,7 @@ await repo.FetchOrigin( var progressSection2 = jobProgressReporter?.CreateSection("Checking out OpenDream version", 0.5f); var committish = version.SourceSHA - ?? $"{GeneralConfiguration.OpenDreamGitTagPrefix}{version.Version.Semver()}"; + ?? $"{GeneralConfiguration.OpenDreamGitTagPrefix}{version.Version!.Semver()}"; await repo.CheckoutObject( committish, @@ -269,8 +267,7 @@ await HandleExtremelyLongPathOperation( using (cancellationToken.Register(() => buildProcess.Terminate())) buildExitCode = await buildProcess.Lifetime; - string output; - + string? output; if (!GeneralConfiguration.OpenDreamSuppressInstallOutput) { var buildOutputTask = buildProcess.GetCombinedOutput(cancellationToken); From ba7710fc9dfa56962775013a08963d1bb7925618 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 20:49:30 -0500 Subject: [PATCH 633/717] Nullify `PosixByondInstaller` --- .../Components/Engine/PosixByondInstaller.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs index 165be04ada3..037cacd437c 100644 --- a/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/PosixByondInstaller.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// @@ -95,7 +93,7 @@ async ValueTask WriteAndMakeExecutable(string pathToScript, string script) var basePath = IOManager.ConcatPath(path, ByondBinPath); var ddTask = WriteAndMakeExecutable( - IOManager.ConcatPath(basePath, GetDreamDaemonName(version.Version, out _)), + IOManager.ConcatPath(basePath, GetDreamDaemonName(version.Version!, out _)), dreamDaemonScript); var dmTask = WriteAndMakeExecutable( From 606bea53acf6269b5a2f5c2540454d08abf7cea8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 20:49:56 -0500 Subject: [PATCH 634/717] Nullify `RepositoryEngineInstallationData` --- .../Components/Engine/RepositoryEngineInstallationData.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs b/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs index 2c96b6f3113..88fbb779117 100644 --- a/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs +++ b/src/Tgstation.Server.Host/Components/Engine/RepositoryEngineInstallationData.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// From 5fb9b773d47e7f9e11b88c7c9335b433c3abd59f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 20:50:22 -0500 Subject: [PATCH 635/717] Nullify `WindowsByondInstaller` --- .../Components/Engine/WindowsByondInstaller.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs index 2c3aad65bc8..87424718d5d 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsByondInstaller.cs @@ -15,8 +15,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// @@ -245,7 +243,7 @@ async ValueTask InstallDirectX(string path, CancellationToken cancellationToken) /// A representing the running operation. async ValueTask AddDreamDaemonToFirewall(EngineVersion version, string path, CancellationToken cancellationToken) { - var dreamDaemonName = GetDreamDaemonName(version.Version, out var usesDDExe); + var dreamDaemonName = GetDreamDaemonName(version.Version!, out var usesDDExe); var dreamDaemonPath = IOManager.ResolvePath( IOManager.ConcatPath( From 60b636e32e0b15f85b59ee6437e80f73c715efcb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 20:50:43 -0500 Subject: [PATCH 636/717] Nullify `WindowsOpenDreamInstaller` --- .../Components/Engine/WindowsOpenDreamInstaller.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index d343c32802f..25968446fe0 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -15,8 +15,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// From 7c37bd80dc1b08507685b24f61729c3651b1449c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 22 Dec 2023 20:51:10 -0500 Subject: [PATCH 637/717] Nullify `ZipStreamEngineInstallationData` --- .../Components/Engine/ZipStreamEngineInstallationData.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs b/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs index 71c26b92ef4..292b7259817 100644 --- a/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs +++ b/src/Tgstation.Server.Host/Components/Engine/ZipStreamEngineInstallationData.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Components.Engine { /// From 51d78df776d2132184d82c81066c1e190f50a000 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 09:51:05 -0500 Subject: [PATCH 638/717] Make `EventConsumer` thread safe --- src/Tgstation.Server.Host/Components/Events/EventConsumer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs b/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs index 6c8b6811281..559e584a27f 100644 --- a/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs +++ b/src/Tgstation.Server.Host/Components/Events/EventConsumer.cs @@ -50,10 +50,9 @@ public async ValueTask HandleEvent(EventType eventType, IEnumerable par public void SetWatchdog(IWatchdog watchdog) { ArgumentNullException.ThrowIfNull(watchdog); - if (this.watchdog != null) + var oldWatchdog = Interlocked.CompareExchange(ref this.watchdog, watchdog, null); + if (oldWatchdog != null) throw new InvalidOperationException("watchdog already set!"); - - this.watchdog = watchdog; } } } From a6d557eabe4a50c806e6a55b25cd6cf8dd2da702 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 09:52:55 -0500 Subject: [PATCH 639/717] Nullify `BridgeParameters` --- .../Components/Interop/Bridge/BridgeParameters.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs index a1475ed1f92..e633a4c240f 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Components.Chat.Commands; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Bridge { /// @@ -26,12 +24,12 @@ public sealed class BridgeParameters : DMApiParameters /// /// The DMAPI for requests. /// - public Version Version { get; set; } + public Version? Version { get; set; } /// /// The DMAPI s for requests. /// - public ICollection CustomCommands { get; set; } + public ICollection? CustomCommands { get; set; } /// /// The minimum required level for requests. @@ -41,12 +39,12 @@ public sealed class BridgeParameters : DMApiParameters /// /// The for requests. /// - public ChatMessage ChatMessage { get; set; } + public ChatMessage? ChatMessage { get; set; } /// /// The for requests. /// - public ChunkData Chunk { get; set; } + public ChunkData? Chunk { get; set; } /// /// The port that should be used to send world topics, if not the default. From c192bd543bdccabeaa993a6b1d361cd825305cf2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 09:53:11 -0500 Subject: [PATCH 640/717] Nullify `BridgeRegistration` --- .../Components/Interop/Bridge/BridgeRegistration.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeRegistration.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeRegistration.cs index 38acfd827d3..1ba9673ee61 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeRegistration.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeRegistration.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Bridge { /// From 59306d1cbd04e6e3fe47a9d02ee7ccde757058b6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 09:55:00 -0500 Subject: [PATCH 641/717] Nullify `BridgeResponse` --- .../Components/Interop/Bridge/BridgeResponse.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeResponse.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeResponse.cs index 27113567b26..620241fafb1 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeResponse.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeResponse.cs @@ -1,7 +1,5 @@ using System.Collections.Generic; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Bridge { /// @@ -17,11 +15,11 @@ public class BridgeResponse : DMApiResponse, IMissingPayloadsCommunication /// /// The for requests. /// - public RuntimeInformation RuntimeInformation { get; set; } + public RuntimeInformation? RuntimeInformation { get; set; } /// /// The s missing from a chunked request. /// - public IReadOnlyCollection MissingChunks { get; set; } + public IReadOnlyCollection? MissingChunks { get; set; } } } From f2f576fd7884867bdf2aad9ff08b9439bba7781f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 09:55:32 -0500 Subject: [PATCH 642/717] Nullify `IBridgeDispatcher` --- .../Components/Interop/Bridge/IBridgeDispatcher.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeDispatcher.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeDispatcher.cs index 166daa4a217..80355834425 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeDispatcher.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeDispatcher.cs @@ -1,8 +1,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Bridge { /// @@ -16,6 +14,6 @@ public interface IBridgeDispatcher /// The to handle. /// The for the operation. /// A resulting in the for the request or if the request could not be dispatched. - ValueTask ProcessBridgeRequest(BridgeParameters parameters, CancellationToken cancellationToken); + ValueTask ProcessBridgeRequest(BridgeParameters parameters, CancellationToken cancellationToken); } } From e39577c7f45fcde20573d62b04bf3aa23161cc35 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 09:55:54 -0500 Subject: [PATCH 643/717] Nullify `IBridgeRegistration` --- .../Components/Interop/Bridge/IBridgeRegistration.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeRegistration.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeRegistration.cs index 50f17cf9120..189846f0810 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeRegistration.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/IBridgeRegistration.cs @@ -1,7 +1,5 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Bridge { /// From d854a630ce3e623aee3d4960b31a46cababa728c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:02:05 -0500 Subject: [PATCH 644/717] Nullify `RuntimeInformation` --- .../Components/Interop/Bridge/RuntimeInformation.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/RuntimeInformation.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/RuntimeInformation.cs index a24a17a614f..a011dad75a4 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/RuntimeInformation.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/RuntimeInformation.cs @@ -9,8 +9,6 @@ using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Bridge { /// @@ -93,11 +91,11 @@ public RuntimeInformation( OriginCommitSha = dmbProvider.CompileJob.RevisionInformation.OriginCommitSha, }; - TestMerges = (IReadOnlyCollection)dmbProvider + TestMerges = (IReadOnlyCollection?)dmbProvider .CompileJob .RevisionInformation - .ActiveTestMerges? - .Select(x => x.TestMerge) + .ActiveTestMerges + ?.Select(x => x.TestMerge) .Select(x => new TestMergeInformation(x, Revision)) .ToList() ?? Array.Empty(); From fadecee5784720fb993de7ede03d95eae12fe2d3 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:06:19 -0500 Subject: [PATCH 645/717] Nullify `TestMergeInformation` --- .../Components/Interop/Bridge/TestMergeInformation.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/TestMergeInformation.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/TestMergeInformation.cs index 3543f052bbf..4537c56bd92 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/TestMergeInformation.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/TestMergeInformation.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Api.Models.Internal; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Bridge { /// @@ -20,10 +18,10 @@ public sealed class TestMergeInformation : TestMergeModelBase /// /// Backing field for needed to continue to support DMAPI 5. /// - public string PullRequestRevision { get; set; } + public string? PullRequestRevision { get; set; } /// - public override string TargetCommitSha + public override string? TargetCommitSha { get => PullRequestRevision; set => PullRequestRevision = value; From d663b97aedf83a80a133f8c5ceb4a1e9a0d25310 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:06:49 -0500 Subject: [PATCH 646/717] Nullify `ChatCommand` --- .../Components/Interop/Topic/ChatCommand.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/ChatCommand.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/ChatCommand.cs index 34aeed50e73..5f50d6bba81 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/ChatCommand.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/ChatCommand.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Components.Chat; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Topic { /// From 7747df9afda9dcc0800578830f802b4bba92eeb4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:07:39 -0500 Subject: [PATCH 647/717] Nullify `ChunkedTopicParameters` --- .../Components/Interop/Topic/ChunkedTopicParameters.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/ChunkedTopicParameters.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/ChunkedTopicParameters.cs index 99bf573d9bc..0940281ecea 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/ChunkedTopicParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/ChunkedTopicParameters.cs @@ -1,7 +1,5 @@ using System.Collections.Generic; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Topic { /// @@ -10,7 +8,7 @@ namespace Tgstation.Server.Host.Components.Interop.Topic sealed class ChunkedTopicParameters : TopicParameters, IMissingPayloadsCommunication, IChunkPayloadId { /// - public IReadOnlyCollection MissingChunks { get; set; } + public IReadOnlyCollection? MissingChunks { get; set; } /// public uint? PayloadId { get; set; } From 6f9808f2b859ec721acca71dc368b52c75b3c812 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:09:00 -0500 Subject: [PATCH 648/717] Nullify `EventNotification` --- .../Components/Interop/Topic/EventNotification.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/EventNotification.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/EventNotification.cs index 6977a275547..75eb3bc9f41 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/EventNotification.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/EventNotification.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Components.Events; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Topic { /// @@ -22,14 +20,14 @@ sealed class EventNotification /// /// The set of parameters. /// - public IReadOnlyCollection Parameters { get; } + public IReadOnlyCollection Parameters { get; } /// /// Initializes a new instance of the class. /// /// The value of . /// The that forms the value of . - public EventNotification(EventType eventType, IEnumerable parameters = null) + public EventNotification(EventType eventType, IEnumerable parameters) { Type = eventType; Parameters = parameters?.ToList() ?? throw new ArgumentNullException(nameof(parameters)); From 2f90ef455355c990b3367da4f681cdf236aee7e6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:09:22 -0500 Subject: [PATCH 649/717] Nullify `TopicCommandType` --- .../Components/Interop/Topic/TopicCommandType.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicCommandType.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicCommandType.cs index 08d8917a660..286c605d07d 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicCommandType.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicCommandType.cs @@ -1,7 +1,5 @@ using System; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Topic { /// From aea5ecac1c636a0eef3698d749c7f95f83d74a7e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:10:06 -0500 Subject: [PATCH 650/717] Nullify `TopicParameters` --- .../Components/Interop/Topic/TopicParameters.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs index 8674e0679d4..f84a404289a 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Components.Session; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Topic { /// @@ -22,12 +20,12 @@ class TopicParameters : DMApiParameters /// /// The for requests. /// - public ChatCommand ChatCommand { get; } + public ChatCommand? ChatCommand { get; } /// /// The for requests. /// - public EventNotification EventNotification { get; } + public EventNotification? EventNotification { get; } /// /// The new port for or requests. @@ -42,27 +40,27 @@ class TopicParameters : DMApiParameters /// /// The new for requests. /// - public string NewInstanceName { get; } + public string? NewInstanceName { get; } /// /// The message to broadcast for requests. /// - public string BroadcastMessage { get; } + public string? BroadcastMessage { get; } /// /// The for requests. /// - public ChatUpdate ChatUpdate { get; } + public ChatUpdate? ChatUpdate { get; } /// /// The new server after a reattach. /// - public Version NewServerVersion { get; } + public Version? NewServerVersion { get; } /// /// The for a partial request. /// - public ChunkData Chunk { get; } + public ChunkData? Chunk { get; } /// /// Whether or not the constitute a priority request. From 4c3de49eda7dbba25477e985e3c751dbdb32d78d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:10:35 -0500 Subject: [PATCH 651/717] Nullify `TopicResponse` --- .../Components/Interop/Topic/TopicResponse.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicResponse.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicResponse.cs index 3b936b514ea..12db6f3ef17 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicResponse.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicResponse.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Components.Chat.Commands; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop.Topic { /// @@ -14,29 +12,29 @@ sealed class TopicResponse : DMApiResponse, IMissingPayloadsCommunication /// /// The text to reply with as the result of a request, if any. Deprecated circa Interop 5.4.0. /// - public string CommandResponseMessage { get; set; } + public string? CommandResponseMessage { get; set; } /// /// The response from a . Added in Interop 5.4.0. /// - public ChatMessage CommandResponse { get; set; } + public ChatMessage? CommandResponse { get; set; } /// /// The s to send as the result of a request, if any. /// - public ICollection ChatResponses { get; set; } + public ICollection? ChatResponses { get; set; } /// /// The DMAPI s for requests. /// - public ICollection CustomCommands { get; set; } + public ICollection? CustomCommands { get; set; } /// /// The for a partial response. /// - public ChunkData Chunk { get; set; } + public ChunkData? Chunk { get; set; } /// - public IReadOnlyCollection MissingChunks { get; set; } + public IReadOnlyCollection? MissingChunks { get; set; } } } From e2dba1ccbc60aa6e0d6253a0659f5813f6b18e34 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:11:23 -0500 Subject: [PATCH 652/717] Nullify `ChatEmbed` --- .../Components/Interop/ChatEmbed.cs | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatEmbed.cs b/src/Tgstation.Server.Host/Components/Interop/ChatEmbed.cs index e76c2bcbd87..41563191f30 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatEmbed.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatEmbed.cs @@ -1,7 +1,5 @@ using System.Collections.Generic; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop { /// @@ -12,63 +10,63 @@ public sealed class ChatEmbed /// /// The title of the embed. /// - public string Title { get; set; } + public string? Title { get; set; } /// /// The description of the embed. /// - public string Description { get; set; } + public string? Description { get; set; } /// /// The URL of the embed. /// #pragma warning disable CA1056 // Uri properties should not be strings - public string Url { get; set; } + public string? Url { get; set; } #pragma warning restore CA1056 // Uri properties should not be strings /// /// The ISO 8601 timestamp of the embed. /// - public string Timestamp { get; set; } + public string? Timestamp { get; set; } /// /// The colour of the embed in the format hex "#AARRGGBB". /// - public string Colour { get; set; } + public string? Colour { get; set; } /// /// The . /// - public ChatEmbedFooter Footer { get; set; } + public ChatEmbedFooter? Footer { get; set; } /// /// The for an image. /// - public ChatEmbedMedia Image { get; set; } + public ChatEmbedMedia? Image { get; set; } /// /// The for a thumbnail. /// - public ChatEmbedMedia Thumbnail { get; set; } + public ChatEmbedMedia? Thumbnail { get; set; } /// /// The for a video. /// - public ChatEmbedMedia Video { get; set; } + public ChatEmbedMedia? Video { get; set; } /// /// The . /// - public ChatEmbedProvider Provider { get; set; } + public ChatEmbedProvider? Provider { get; set; } /// /// The . /// - public ChatEmbedAuthor Author { get; set; } + public ChatEmbedAuthor? Author { get; set; } /// /// The s. /// - public ICollection Fields { get; set; } + public ICollection? Fields { get; set; } } } From b5b408fc1efb3ad2d7d33840aefd1ff6813d5cf1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:11:45 -0500 Subject: [PATCH 653/717] Nullify `ChatEmbedAuthor` --- .../Components/Interop/ChatEmbedAuthor.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedAuthor.cs b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedAuthor.cs index 97b5d26fd4f..d136b895b01 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedAuthor.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedAuthor.cs @@ -1,6 +1,4 @@ -#nullable disable - -namespace Tgstation.Server.Host.Components.Interop +namespace Tgstation.Server.Host.Components.Interop { /// /// Represents information about a author. @@ -11,12 +9,12 @@ public sealed class ChatEmbedAuthor : ChatEmbedProvider /// Gets the icon URL of the author. /// #pragma warning disable CA1056 // Uri properties should not be strings - public string IconUrl { get; set; } + public string? IconUrl { get; set; } /// /// Gets the proxied icon URL of the thumbnail. /// - public string ProxyIconUrl { get; set; } + public string? ProxyIconUrl { get; set; } #pragma warning restore CA1056 // Uri properties should not be strings } } From 4bfc321e45c5c6d31386095aad2ac4fcc8fc1279 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:12:31 -0500 Subject: [PATCH 654/717] Nullify `ChatEmbedField` --- .../Components/Chat/Providers/DiscordProvider.cs | 2 +- .../Components/Interop/ChatEmbedField.cs | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 047febbe00f..1ee21f9ca0a 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -995,7 +995,7 @@ Optional> ConvertEmbed(ChatEmbed embed) if (invalid) continue; - fields.Add(new EmbedField(field.Name, field.Value) + fields.Add(new EmbedField(field.Name!, field.Value!) { IsInline = field.IsInline ?? default(Optional), }); diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedField.cs b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedField.cs index f5845579920..70b3c37c9fc 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedField.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedField.cs @@ -1,6 +1,4 @@ -#nullable disable - -namespace Tgstation.Server.Host.Components.Interop +namespace Tgstation.Server.Host.Components.Interop { /// /// Represents a field in a . @@ -10,12 +8,12 @@ public sealed class ChatEmbedField /// /// Gets the name of the field. /// - public string Name { get; set; } + public string? Name { get; set; } /// /// Gets the value of the field. /// - public string Value { get; set; } + public string? Value { get; set; } /// /// Gets a value indicating whether the field should display inline. From 82d1b3090fb548560e5785a2ac1192ba29c36668 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:14:02 -0500 Subject: [PATCH 655/717] Nullify `ChatEmbedFooter` --- .../Components/Chat/Providers/DiscordProvider.cs | 2 +- .../Components/Interop/ChatEmbedFooter.cs | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 1ee21f9ca0a..b21202ed371 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -1045,7 +1045,7 @@ Optional> ConvertEmbed(ChatEmbed embed) Description = embed.Description ?? default(Optional), Fields = fields ?? default(Optional>), Footer = embed.Footer != null - ? (Optional)new EmbedFooter(embed.Footer.Text) + ? (Optional)new EmbedFooter(embed.Footer.Text!) { IconUrl = embed.Footer.IconUrl ?? default(Optional), ProxyIconUrl = embed.Footer.ProxyIconUrl ?? default(Optional), diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedFooter.cs b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedFooter.cs index 2105603d92b..57d45ec7eba 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedFooter.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedFooter.cs @@ -1,6 +1,4 @@ -#nullable disable - -namespace Tgstation.Server.Host.Components.Interop +namespace Tgstation.Server.Host.Components.Interop { /// /// Represents a footer in a . @@ -10,18 +8,18 @@ public sealed class ChatEmbedFooter /// /// Gets the text of the footer. /// - public string Text { get; set; } + public string? Text { get; set; } /// /// Gets the URL of the footer icon. Only supports http(s) and attachments. /// #pragma warning disable CA1056 // Uri properties should not be strings - public string IconUrl { get; set; } + public string? IconUrl { get; set; } /// /// Gets the proxied icon URL. /// - public string ProxyIconUrl { get; set; } + public string? ProxyIconUrl { get; set; } #pragma warning restore CA1056 // Uri properties should not be strings } } From e9b6cbdc66d44867099fff60baeb1c2df7c91911 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:14:50 -0500 Subject: [PATCH 656/717] Nullify `ChatEmbedFooter` --- .../Components/Chat/Providers/DiscordProvider.cs | 4 ++-- .../Components/Interop/ChatEmbedMedia.cs | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index b21202ed371..610baacc985 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -1052,7 +1052,7 @@ Optional> ConvertEmbed(ChatEmbed embed) } : default, Image = embed.Image != null - ? new EmbedImage(embed.Image.Url) + ? new EmbedImage(embed.Image.Url!) { Width = embed.Image.Width ?? default(Optional), Height = embed.Image.Height ?? default(Optional), @@ -1067,7 +1067,7 @@ Optional> ConvertEmbed(ChatEmbed embed) } : default(Optional), Thumbnail = embed.Thumbnail != null - ? new EmbedThumbnail(embed.Thumbnail.Url) + ? new EmbedThumbnail(embed.Thumbnail.Url!) { Width = embed.Thumbnail.Width ?? default(Optional), Height = embed.Thumbnail.Height ?? default(Optional), diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedMedia.cs b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedMedia.cs index ebab7bfa805..c031a01e92b 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedMedia.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedMedia.cs @@ -1,6 +1,4 @@ -#nullable disable - -namespace Tgstation.Server.Host.Components.Interop +namespace Tgstation.Server.Host.Components.Interop { /// /// Represents information about a thumbnail in a . @@ -11,12 +9,12 @@ public class ChatEmbedMedia /// Gets the source URL of the media. Only supports http(s) and attachments. /// #pragma warning disable CA1056 // Uri properties should not be strings - public string Url { get; set; } + public string? Url { get; set; } /// /// Gets the proxied URL of the media. /// - public string ProxyUrl { get; set; } + public string? ProxyUrl { get; set; } #pragma warning restore CA1056 // Uri properties should not be strings /// From 34571a19cd35fa8ba8a4d63f0e4daff7b2a47570 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:15:32 -0500 Subject: [PATCH 657/717] Nullify `ChatEmbedProvider` --- .../Components/Chat/Providers/DiscordProvider.cs | 2 +- .../Components/Interop/ChatEmbedProvider.cs | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 610baacc985..02914f87d71 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -1034,7 +1034,7 @@ Optional> ConvertEmbed(ChatEmbed embed) var discordEmbed = new Embed { Author = embed.Author != null - ? new EmbedAuthor(embed.Author.Name) + ? new EmbedAuthor(embed.Author.Name!) { IconUrl = embed.Author.IconUrl ?? default(Optional), ProxyIconUrl = embed.Author.ProxyIconUrl ?? default(Optional), diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedProvider.cs b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedProvider.cs index c7a29b039ea..bc4dba30d76 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatEmbedProvider.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatEmbedProvider.cs @@ -1,6 +1,4 @@ -#nullable disable - -namespace Tgstation.Server.Host.Components.Interop +namespace Tgstation.Server.Host.Components.Interop { /// /// Represents information about a provider. @@ -10,13 +8,13 @@ public class ChatEmbedProvider /// /// Gets the name of the provider. /// - public string Name { get; set; } + public string? Name { get; set; } /// /// Gets the URL of the provider. /// #pragma warning disable CA1056 // Uri properties should not be strings - public string Url { get; set; } + public string? Url { get; set; } #pragma warning restore CA1056 // Uri properties should not be strings } } From 617dea50c3e420c987d24ac0efad82747226bbd1 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:15:56 -0500 Subject: [PATCH 658/717] Nullify `ChatMessage` --- src/Tgstation.Server.Host/Components/Interop/ChatMessage.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatMessage.cs b/src/Tgstation.Server.Host/Components/Interop/ChatMessage.cs index 2178cc1a1d4..c84e44e6cc0 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatMessage.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatMessage.cs @@ -1,7 +1,5 @@ using System.Collections.Generic; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop { /// @@ -12,6 +10,6 @@ public sealed class ChatMessage : MessageContent /// /// The of s to sent the to. Must be safe to parse as s. /// - public ICollection ChannelIds { get; set; } + public ICollection? ChannelIds { get; set; } } } From 545717fc4835ce04c7e611e6df7ccaf853dee3eb Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:16:28 -0500 Subject: [PATCH 659/717] Nullify `ChatUpdate` --- src/Tgstation.Server.Host/Components/Interop/ChatUpdate.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/ChatUpdate.cs b/src/Tgstation.Server.Host/Components/Interop/ChatUpdate.cs index af902de7b60..12e9b408abb 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChatUpdate.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChatUpdate.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Components.Chat; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop { /// From 62ef4e3b9b3cd8a45cf9b74d76e1b05d6c740d2a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:16:47 -0500 Subject: [PATCH 660/717] Nullify `ChunkData` --- src/Tgstation.Server.Host/Components/Interop/ChunkData.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/ChunkData.cs b/src/Tgstation.Server.Host/Components/Interop/ChunkData.cs index 8c442413c5f..409179b6606 100644 --- a/src/Tgstation.Server.Host/Components/Interop/ChunkData.cs +++ b/src/Tgstation.Server.Host/Components/Interop/ChunkData.cs @@ -1,6 +1,4 @@ -#nullable disable - -namespace Tgstation.Server.Host.Components.Interop +namespace Tgstation.Server.Host.Components.Interop { /// /// A packet of a split serialized set of data. @@ -16,6 +14,6 @@ public sealed class ChunkData : ChunkSetInfo /// /// The partial JSON payload of the chunk. /// - public string Payload { get; set; } + public string? Payload { get; set; } } } From f847ec6b6e8b7997552e8e25acfc203c1c177d4b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:20:01 -0500 Subject: [PATCH 661/717] Nullify `Chunker` --- .../Components/Interop/Chunker.cs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Chunker.cs b/src/Tgstation.Server.Host/Components/Interop/Chunker.cs index df02f84e61c..c95d97b9e6f 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Chunker.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Chunker.cs @@ -7,8 +7,6 @@ using Newtonsoft.Json; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop { /// @@ -16,6 +14,11 @@ namespace Tgstation.Server.Host.Components.Interop /// abstract class Chunker { + /// + /// The for the . + /// + protected ILogger Logger { get; } + /// /// Gets a payload ID for use in a new . /// @@ -41,11 +44,6 @@ protected uint NextPayloadId /// uint highestSeenPayloadId; - /// - /// The for the . - /// - protected ILogger Logger { get; } - /// /// Initializes a new instance of the class. /// @@ -67,7 +65,7 @@ protected Chunker(ILogger logger) /// The for the operation. /// A resulting in the for the chunked request. protected async ValueTask ProcessChunk( - Func> completionCallback, + Func> completionCallback, Func chunkErrorCallback, ChunkData chunk, CancellationToken cancellationToken) @@ -82,6 +80,9 @@ protected async ValueTask ProcessChunk( if (!chunk.SequenceId.HasValue) return chunkErrorCallback("Missing chunk sequenceId!"); + if (chunk.Payload == null) + return chunkErrorCallback("Missing chunk payload!"); + ChunkSetInfo requestInfo; string[] payloads; lock (chunkSets) @@ -104,13 +105,13 @@ protected async ValueTask ProcessChunk( if (chunk.TotalChunks != requestInfo.TotalChunks) { - chunkSets.Remove(requestInfo.PayloadId.Value); + chunkSets.Remove(requestInfo.PayloadId!.Value); return chunkErrorCallback("Received differing total chunks for same payloadId! Invalidating payloadId!"); } if (payloads[chunk.SequenceId.Value] != null && payloads[chunk.SequenceId.Value] != chunk.Payload) { - chunkSets.Remove(requestInfo.PayloadId.Value); + chunkSets.Remove(requestInfo.PayloadId!.Value); return chunkErrorCallback("Received differing payload for same sequenceId! Invalidating payloadId!"); } @@ -127,10 +128,10 @@ protected async ValueTask ProcessChunk( }; Logger.LogTrace("Received all chunks for P{payloadId}, processing request...", requestInfo.PayloadId); - chunkSets.Remove(requestInfo.PayloadId.Value); + chunkSets.Remove(requestInfo.PayloadId!.Value); } - TCommunication completedCommunication; + TCommunication? completedCommunication; var fullCommunicationJson = String.Concat(payloads); try { From 0d64959ebdbab705cf39122e9f4b173c6a7fad1f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:21:24 -0500 Subject: [PATCH 662/717] Nullify `DMApiConstants` --- .../Components/Interop/DMApiConstants.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs index def2cb27e7c..7386e856691 100644 --- a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs +++ b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Host.Extensions.Converters; using Tgstation.Server.Host.Properties; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop { /// @@ -42,12 +40,12 @@ static class DMApiConstants public const uint MaximumBridgeRequestLength = 8198; /// - /// The maximum length in bytes of a payload. + /// The maximum length in bytes of a payload. /// public const uint MaximumTopicRequestLength = 65528; /// - /// The maximum length in bytes of a response. + /// The maximum length in bytes of a response. /// public const uint MaximumTopicResponseLength = 65529; From aa0fe2ed72a6a7d81081e72f736bf1befd807619 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:30:44 -0500 Subject: [PATCH 663/717] Nullify `DMApiParameters` --- .../Components/InstanceManager.cs | 16 +++++++++++++--- .../Components/Interop/DMApiParameters.cs | 4 +--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index eeadde0c30a..cc0dd099726 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -510,6 +510,13 @@ async ValueTask OfflineInstanceImmediate(IInstance instance, CancellationToken c { ArgumentNullException.ThrowIfNull(parameters); + var accessIdentifier = parameters.AccessIdentifier; + if (accessIdentifier == null) + { + logger.LogWarning("Received invalid bridge request with null access identifier!"); + return null; + } + IBridgeHandler? bridgeHandler = null; for (var i = 0; bridgeHandler == null && i < 30; ++i) { @@ -517,7 +524,7 @@ async ValueTask OfflineInstanceImmediate(IInstance instance, CancellationToken c // This is a stopgap Task delayTask = Task.CompletedTask; lock (bridgeHandlers) - if (!bridgeHandlers.TryGetValue(parameters.AccessIdentifier, out bridgeHandler)) + if (!bridgeHandlers.TryGetValue(accessIdentifier, out bridgeHandler)) delayTask = asyncDelayer.Delay(TimeSpan.FromMilliseconds(100), cancellationToken); await delayTask; @@ -525,9 +532,9 @@ async ValueTask OfflineInstanceImmediate(IInstance instance, CancellationToken c if (bridgeHandler == null) lock (bridgeHandlers) - if (!bridgeHandlers.TryGetValue(parameters.AccessIdentifier, out bridgeHandler)) + if (!bridgeHandlers.TryGetValue(accessIdentifier, out bridgeHandler)) { - logger.LogWarning("Received invalid bridge request with access identifier: {accessIdentifier}", parameters.AccessIdentifier); + logger.LogWarning("Received invalid bridge request with access identifier: {accessIdentifier}", accessIdentifier); return null; } @@ -540,6 +547,9 @@ public IBridgeRegistration RegisterHandler(IBridgeHandler bridgeHandler) ArgumentNullException.ThrowIfNull(bridgeHandler); var accessIdentifier = bridgeHandler.DMApiParameters.AccessIdentifier; + if (accessIdentifier == null) + throw new InvalidOperationException("Attempted bridge registration with null AccessIdentifier!"); + lock (bridgeHandlers) { bridgeHandlers.Add(accessIdentifier, bridgeHandler); diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiParameters.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiParameters.cs index 55954dd38de..2a31c9efbc5 100644 --- a/src/Tgstation.Server.Host/Components/Interop/DMApiParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/DMApiParameters.cs @@ -1,7 +1,5 @@ using System.ComponentModel.DataAnnotations; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop { /// @@ -13,6 +11,6 @@ public abstract class DMApiParameters /// Used to identify and authenticate the DreamDaemon instance. /// [Required] - public string AccessIdentifier { get; set; } + public string? AccessIdentifier { get; set; } } } From b6cb32c54a1367116a834921e5a8907a911c1ada Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:31:04 -0500 Subject: [PATCH 664/717] Nullify `DMApiResponse` --- .../Components/Interop/DMApiResponse.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiResponse.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiResponse.cs index 1196d8aa6fa..e6c75020639 100644 --- a/src/Tgstation.Server.Host/Components/Interop/DMApiResponse.cs +++ b/src/Tgstation.Server.Host/Components/Interop/DMApiResponse.cs @@ -1,6 +1,4 @@ -#nullable disable - -namespace Tgstation.Server.Host.Components.Interop +namespace Tgstation.Server.Host.Components.Interop { /// /// Common base for interop responses. @@ -10,6 +8,6 @@ public abstract class DMApiResponse /// /// Any errors in the client's parameters. /// - public string ErrorMessage { get; set; } + public string? ErrorMessage { get; set; } } } From 047618c4c46fd94a56e7f40735c8adb1263a168b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:31:19 -0500 Subject: [PATCH 665/717] Nullify `IMissingPayloadsCommunication` --- .../Components/Interop/IMissingPayloadsCommunication.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/IMissingPayloadsCommunication.cs b/src/Tgstation.Server.Host/Components/Interop/IMissingPayloadsCommunication.cs index 77c3ebff3fa..7adf7d9cce0 100644 --- a/src/Tgstation.Server.Host/Components/Interop/IMissingPayloadsCommunication.cs +++ b/src/Tgstation.Server.Host/Components/Interop/IMissingPayloadsCommunication.cs @@ -1,7 +1,5 @@ using System.Collections.Generic; -#nullable disable - namespace Tgstation.Server.Host.Components.Interop { /// @@ -12,6 +10,6 @@ interface IMissingPayloadsCommunication /// /// The s missing from a chunked request. /// - IReadOnlyCollection MissingChunks { get; set; } + IReadOnlyCollection? MissingChunks { get; set; } } } From ffbf0f5ba77b1eecedc0bcce71692740693c2cc0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:34:49 -0500 Subject: [PATCH 666/717] Nullify `MessageContent` --- .../Chat/Providers/DiscordProvider.cs | 18 +++++++++++++++++- .../Components/Interop/MessageContent.cs | 8 +++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs index 02914f87d71..6f7ad59c5a8 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs @@ -218,6 +218,22 @@ public override async ValueTask SendMessage(Message? replyTo, MessageContent mes var channelsClient = serviceProvider.GetRequiredService(); async ValueTask SendToChannel(Snowflake channelId) { + if (message.Text == null) + { + Logger.LogWarning( + "Failed to send to channel {channelId}: Message was null!", + channelId); + + await channelsClient.CreateMessageAsync( + channelId, + "TGS: Could not send message to Discord. Message was `null`!", + messageReference: replyToReference, + allowedMentions: allowedMentions, + ct: cancellationToken); + + return; + } + var result = await channelsClient.CreateMessageAsync( channelId, message.Text, @@ -940,7 +956,7 @@ List BuildUpdateEmbedFields( /// The to convert. /// The parameter for sending a single . #pragma warning disable CA1502 - Optional> ConvertEmbed(ChatEmbed embed) + Optional> ConvertEmbed(ChatEmbed? embed) { if (embed == null) return default; diff --git a/src/Tgstation.Server.Host/Components/Interop/MessageContent.cs b/src/Tgstation.Server.Host/Components/Interop/MessageContent.cs index 73e29809068..6b04fb10ae9 100644 --- a/src/Tgstation.Server.Host/Components/Interop/MessageContent.cs +++ b/src/Tgstation.Server.Host/Components/Interop/MessageContent.cs @@ -1,6 +1,4 @@ -#nullable disable - -namespace Tgstation.Server.Host.Components.Interop +namespace Tgstation.Server.Host.Components.Interop { /// /// Represents a message to send to a chat provider. @@ -10,11 +8,11 @@ public class MessageContent /// /// The message . /// - public string Text { get; set; } + public string? Text { get; set; } /// /// The . /// - public ChatEmbed Embed { get; set; } + public ChatEmbed? Embed { get; set; } } } From c4da6df175cd090e0cd395a5fa52ffc8b9106920 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 10:35:06 -0500 Subject: [PATCH 667/717] Simplify a null check --- src/Tgstation.Server.Host/Components/InstanceManager.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs index cc0dd099726..613b9d78004 100644 --- a/src/Tgstation.Server.Host/Components/InstanceManager.cs +++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs @@ -546,10 +546,8 @@ public IBridgeRegistration RegisterHandler(IBridgeHandler bridgeHandler) { ArgumentNullException.ThrowIfNull(bridgeHandler); - var accessIdentifier = bridgeHandler.DMApiParameters.AccessIdentifier; - if (accessIdentifier == null) - throw new InvalidOperationException("Attempted bridge registration with null AccessIdentifier!"); - + var accessIdentifier = bridgeHandler.DMApiParameters.AccessIdentifier + ?? throw new InvalidOperationException("Attempted bridge registration with null AccessIdentifier!"); lock (bridgeHandlers) { bridgeHandlers.Add(accessIdentifier, bridgeHandler); From a4258d137e4a28da8bb741124ffcb2eb33a09178 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:02:14 -0500 Subject: [PATCH 668/717] Rework `DMApiParameters.AccessIdentifier` to be properly non-nullble --- .../Interop/Bridge/BridgeParameters.cs | 9 ++++++++ .../Components/Interop/DMApiParameters.cs | 23 +++++++++++++++++-- .../Interop/Topic/TopicParameters.cs | 1 + .../Components/Session/ReattachInformation.cs | 3 +-- .../Components/Session/SessionPersistor.cs | 5 ++-- .../Controllers/BridgeController.cs | 4 ++-- .../Models/ReattachInformation.cs | 20 +++++++++++++++- .../Models/ReattachInformationBase.cs | 15 ++++++++++-- .../Live/Instance/TestBridgeHandler.cs | 13 +++++++---- 9 files changed, 76 insertions(+), 17 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs index e633a4c240f..1240bc81cb9 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Bridge/BridgeParameters.cs @@ -50,5 +50,14 @@ public sealed class BridgeParameters : DMApiParameters /// The port that should be used to send world topics, if not the default. /// public ushort? TopicPort { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The access identifier for the . + public BridgeParameters(string accessIdentifier) + : base(accessIdentifier) + { + } } } diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiParameters.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiParameters.cs index 2a31c9efbc5..64b774aeb51 100644 --- a/src/Tgstation.Server.Host/Components/Interop/DMApiParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/DMApiParameters.cs @@ -1,4 +1,5 @@ -using System.ComponentModel.DataAnnotations; +using System; +using System.ComponentModel.DataAnnotations; namespace Tgstation.Server.Host.Components.Interop { @@ -11,6 +12,24 @@ public abstract class DMApiParameters /// Used to identify and authenticate the DreamDaemon instance. /// [Required] - public string? AccessIdentifier { get; set; } + public string AccessIdentifier { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The value of . + public DMApiParameters(string accessIdentifier) + { + AccessIdentifier = accessIdentifier ?? throw new ArgumentNullException(nameof(accessIdentifier)); + } + + /// + /// Initializes a new instance of the class. + /// + /// For use by EFCore only. + protected DMApiParameters() + { + AccessIdentifier = null!; + } } } diff --git a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs index f84a404289a..bdc8405b022 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Topic/TopicParameters.cs @@ -188,6 +188,7 @@ public TopicParameters() /// /// The value of . protected TopicParameters(TopicCommandType commandType) + : base(String.Empty) // access identifier gets set before send { CommandType = commandType; } diff --git a/src/Tgstation.Server.Host/Components/Session/ReattachInformation.cs b/src/Tgstation.Server.Host/Components/Session/ReattachInformation.cs index 3ddeff51d76..31aa0834b7b 100644 --- a/src/Tgstation.Server.Host/Components/Session/ReattachInformation.cs +++ b/src/Tgstation.Server.Host/Components/Session/ReattachInformation.cs @@ -74,13 +74,12 @@ internal ReattachInformation( RuntimeInformation runtimeInformation, string accessIdentifier, ushort port) + : base(accessIdentifier) { Dmb = dmb ?? throw new ArgumentNullException(nameof(dmb)); ProcessId = process?.Id ?? throw new ArgumentNullException(nameof(process)); RuntimeInformation = runtimeInformation ?? throw new ArgumentNullException(nameof(runtimeInformation)); - AccessIdentifier = accessIdentifier ?? throw new ArgumentNullException(nameof(accessIdentifier)); - LaunchSecurityLevel = runtimeInformation.SecurityLevel; LaunchVisibility = runtimeInformation.Visibility; Port = port; diff --git a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs index 7eebd9a2af2..2cd093c3eea 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs @@ -75,9 +75,8 @@ public ValueTask Save(ReattachInformation reattachInformation, CancellationToken await ClearImpl(db, false, cancellationToken); - var dbReattachInfo = new Models.ReattachInformation + var dbReattachInfo = new Models.ReattachInformation(reattachInformation.AccessIdentifier) { - AccessIdentifier = reattachInformation.AccessIdentifier, CompileJobId = reattachInformation.Dmb.CompileJob.Id.Value, InitialCompileJobId = reattachInformation.InitialDmb?.CompileJob.Id.Value, Port = reattachInformation.Port, @@ -103,7 +102,7 @@ public ValueTask Update(ReattachInformation reattachInformation, CancellationTok logger.LogTrace("Updating reattach information: {info}...", reattachInformation); - var dbReattachInfo = new Models.ReattachInformation + var dbReattachInfo = new Models.ReattachInformation(String.Empty) { Id = reattachInformation.Id.Value, }; diff --git a/src/Tgstation.Server.Host/Controllers/BridgeController.cs b/src/Tgstation.Server.Host/Controllers/BridgeController.cs index c4d33be706e..4b1a1fac3e6 100644 --- a/src/Tgstation.Server.Host/Controllers/BridgeController.cs +++ b/src/Tgstation.Server.Host/Controllers/BridgeController.cs @@ -97,10 +97,10 @@ public async ValueTask Process([FromQuery] string data, Cancellat using (LogContext.PushProperty(SerilogContextHelper.BridgeRequestIterationContextProperty, Interlocked.Increment(ref requestsProcessed))) { - var request = new BridgeParameters(); + BridgeParameters? request; try { - JsonConvert.PopulateObject(data, request, DMApiConstants.SerializerSettings); + request = JsonConvert.DeserializeObject(data, DMApiConstants.SerializerSettings); } catch (Exception ex) { diff --git a/src/Tgstation.Server.Host/Models/ReattachInformation.cs b/src/Tgstation.Server.Host/Models/ReattachInformation.cs index 9454e4acf6c..49360cf3e50 100644 --- a/src/Tgstation.Server.Host/Models/ReattachInformation.cs +++ b/src/Tgstation.Server.Host/Models/ReattachInformation.cs @@ -1,4 +1,5 @@ -using System.ComponentModel.DataAnnotations; +using System; +using System.ComponentModel.DataAnnotations; namespace Tgstation.Server.Host.Models { @@ -27,5 +28,22 @@ public sealed class ReattachInformation : ReattachInformationBase /// The of . /// public long? InitialCompileJobId { get; set; } + + /// + /// Initializes a new instance of the class. + /// + [Obsolete("For use by EFCore only", true)] + public ReattachInformation() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The access identifier for the . + public ReattachInformation(string accessIdentifier) + : base(accessIdentifier) + { + } } } diff --git a/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs b/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs index 3d3d4411cb0..fc6d07a8f30 100644 --- a/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs +++ b/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs @@ -49,19 +49,30 @@ public abstract class ReattachInformationBase : DMApiParameters /// /// Initializes a new instance of the class. /// + /// For use by EFCore only. protected ReattachInformationBase() { } + /// + /// Initializes a new instance of the class. + /// + /// The access identifier for the . + protected ReattachInformationBase(string accessIdentifier) + : base(accessIdentifier) + { + } + /// /// Initializes a new instance of the class. /// /// The to copy values from. protected ReattachInformationBase(ReattachInformationBase copy) + : base(copy == null + ? throw new ArgumentNullException(nameof(copy)) + : copy.AccessIdentifier) { - ArgumentNullException.ThrowIfNull(copy); Id = copy.Id; - AccessIdentifier = copy.AccessIdentifier; Port = copy.Port; TopicPort = copy.TopicPort; ProcessId = copy.ProcessId; diff --git a/tests/Tgstation.Server.Tests/Live/Instance/TestBridgeHandler.cs b/tests/Tgstation.Server.Tests/Live/Instance/TestBridgeHandler.cs index 4276067b192..e00421e295f 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/TestBridgeHandler.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/TestBridgeHandler.cs @@ -15,17 +15,20 @@ namespace Tgstation.Server.Tests.Live.Instance { sealed class TestBridgeHandler : Chunker, IBridgeHandler { - class DMApiParametersImpl : DMApiParameters { } + class DMApiParametersImpl : DMApiParameters + { + public DMApiParametersImpl(string accessIdentifier) + : base(accessIdentifier) + { + } + } class BridgeResponseHack : BridgeResponse { public string IntegrationHack { get; set; } } - public DMApiParameters DMApiParameters => new DMApiParametersImpl - { - AccessIdentifier = accessIdentifier - }; + public DMApiParameters DMApiParameters => new DMApiParametersImpl(accessIdentifier); long lastBridgeRequestSize = 0; From 0f655f14d752d33732264aaf4b7540405c5014b9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:03:28 -0500 Subject: [PATCH 669/717] Nullify `DefaultGitRemoteFeatures` --- .../Components/Repository/DefaultGitRemoteFeatures.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/DefaultGitRemoteFeatures.cs b/src/Tgstation.Server.Host/Components/Repository/DefaultGitRemoteFeatures.cs index c5909b7b840..05d9408a677 100644 --- a/src/Tgstation.Server.Host/Components/Repository/DefaultGitRemoteFeatures.cs +++ b/src/Tgstation.Server.Host/Components/Repository/DefaultGitRemoteFeatures.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Api.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// @@ -23,10 +21,10 @@ sealed class DefaultGitRemoteFeatures : IGitRemoteFeatures public RemoteGitProvider? RemoteGitProvider => Api.Models.RemoteGitProvider.Unknown; /// - public string RemoteRepositoryOwner => null; + public string? RemoteRepositoryOwner => null; /// - public string RemoteRepositoryName => null; + public string? RemoteRepositoryName => null; /// public ValueTask GetTestMerge( From a1f4ed4ab4de0bf11f3cee65b903bac9ca17ff7a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:04:18 -0500 Subject: [PATCH 670/717] Nullify `GitHubRemoteFeatures` --- .../Components/Repository/GitHubRemoteFeatures.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/GitHubRemoteFeatures.cs b/src/Tgstation.Server.Host/Components/Repository/GitHubRemoteFeatures.cs index 2aa9cb33128..609862d9ba9 100644 --- a/src/Tgstation.Server.Host/Components/Repository/GitHubRemoteFeatures.cs +++ b/src/Tgstation.Server.Host/Components/Repository/GitHubRemoteFeatures.cs @@ -9,8 +9,6 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Host.Utils.GitHub; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// @@ -67,9 +65,9 @@ public GitHubRemoteFeatures(IGitHubServiceFactory gitHubServiceFactory, ILogger< ? gitHubServiceFactory.CreateService(repositorySettings.AccessToken) : gitHubServiceFactory.CreateService(); - PullRequest pr = null; - ApiException exception = null; - string errorMessage = null; + PullRequest? pr = null; + ApiException? exception = null; + string? errorMessage = null; try { pr = await gitHubService.GetPullRequest(RemoteRepositoryOwner, RemoteRepositoryName, parameters.Number, cancellationToken); From fc7c8b2c6314eb0f9db9675b0bcf24176dc13ad7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:04:44 -0500 Subject: [PATCH 671/717] Nullify `GitLabRemoteFeatures` --- .../Components/Repository/GitLabRemoteFeatures.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs b/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs index 1f34ceeacbe..def1adbaaf6 100644 --- a/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs +++ b/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs @@ -8,8 +8,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// From 1d43e7a8517ebc2e53ce6c3a156d91eeef77926d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:05:36 -0500 Subject: [PATCH 672/717] Nullify `GitRemoteFeaturesBase` --- .../Components/Repository/GitRemoteFeaturesBase.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesBase.cs b/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesBase.cs index b0adfdb2982..ffbf99fa814 100644 --- a/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesBase.cs +++ b/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesBase.cs @@ -8,8 +8,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// @@ -64,7 +62,7 @@ public GitRemoteFeaturesBase(ILogger logger, Uri remoteUr ArgumentNullException.ThrowIfNull(parameters); ArgumentNullException.ThrowIfNull(repositorySettings); - Models.TestMerge result; + Models.TestMerge? result; lock (cachedLookups) if (cachedLookups.TryGetValue(parameters, out result)) Logger.LogTrace("Using cache for test merge #{0}", parameters.Number); From e536b0238be7f6b66677e24582369b91156902b2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:07:20 -0500 Subject: [PATCH 673/717] Cleanup `GitRemoteFeaturesBase` - Fix logging templates. - Deduplicate constructor code. --- .../Components/Repository/GitHubRemoteFeatures.cs | 13 ------------- .../Components/Repository/GitLabRemoteFeatures.cs | 10 ---------- .../Repository/GitRemoteFeaturesBase.cs | 15 ++++++++++----- 3 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/GitHubRemoteFeatures.cs b/src/Tgstation.Server.Host/Components/Repository/GitHubRemoteFeatures.cs index 609862d9ba9..7a21ebde2b9 100644 --- a/src/Tgstation.Server.Host/Components/Repository/GitHubRemoteFeatures.cs +++ b/src/Tgstation.Server.Host/Components/Repository/GitHubRemoteFeatures.cs @@ -25,12 +25,6 @@ sealed class GitHubRemoteFeatures : GitRemoteFeaturesBase /// public override RemoteGitProvider? RemoteGitProvider => Api.Models.RemoteGitProvider.GitHub; - /// - public override string RemoteRepositoryOwner { get; } - - /// - public override string RemoteRepositoryName { get; } - /// /// The for the . /// @@ -46,13 +40,6 @@ public GitHubRemoteFeatures(IGitHubServiceFactory gitHubServiceFactory, ILogger< : base(logger, remoteUrl) { this.gitHubServiceFactory = gitHubServiceFactory ?? throw new ArgumentNullException(nameof(gitHubServiceFactory)); - - ArgumentNullException.ThrowIfNull(remoteUrl); - - RemoteRepositoryOwner = remoteUrl.Segments[1].TrimEnd('/'); - RemoteRepositoryName = remoteUrl.Segments[2].TrimEnd('/'); - if (RemoteRepositoryName.EndsWith(".git", StringComparison.OrdinalIgnoreCase)) - RemoteRepositoryName = RemoteRepositoryName[0..^4]; } /// diff --git a/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs b/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs index def1adbaaf6..9e468b06e66 100644 --- a/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs +++ b/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs @@ -30,12 +30,6 @@ sealed class GitLabRemoteFeatures : GitRemoteFeaturesBase /// public override RemoteGitProvider? RemoteGitProvider => Api.Models.RemoteGitProvider.GitLab; - /// - public override string RemoteRepositoryOwner { get; } - - /// - public override string RemoteRepositoryName { get; } - /// /// Initializes a new instance of the class. /// @@ -44,10 +38,6 @@ sealed class GitLabRemoteFeatures : GitRemoteFeaturesBase public GitLabRemoteFeatures(ILogger logger, Uri remoteUrl) : base(logger, remoteUrl) { - RemoteRepositoryOwner = remoteUrl.Segments[1].TrimEnd('/'); - RemoteRepositoryName = remoteUrl.Segments[2].TrimEnd('/'); - if (RemoteRepositoryName.EndsWith(".git", StringComparison.OrdinalIgnoreCase)) - RemoteRepositoryName = RemoteRepositoryName[0..^4]; } /// diff --git a/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesBase.cs b/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesBase.cs index ffbf99fa814..d42e9287929 100644 --- a/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesBase.cs +++ b/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesBase.cs @@ -25,10 +25,10 @@ abstract class GitRemoteFeaturesBase : IGitRemoteFeatures public abstract RemoteGitProvider? RemoteGitProvider { get; } /// - public abstract string RemoteRepositoryOwner { get; } + public string RemoteRepositoryOwner { get; } /// - public abstract string RemoteRepositoryName { get; } + public string RemoteRepositoryName { get; } /// /// The for the . @@ -50,6 +50,11 @@ public GitRemoteFeaturesBase(ILogger logger, Uri remoteUr Logger = logger ?? throw new ArgumentNullException(nameof(logger)); ArgumentNullException.ThrowIfNull(remoteUrl); + RemoteRepositoryOwner = remoteUrl.Segments[1].TrimEnd('/'); + RemoteRepositoryName = remoteUrl.Segments[2].TrimEnd('/'); + if (RemoteRepositoryName.EndsWith(".git", StringComparison.OrdinalIgnoreCase)) + RemoteRepositoryName = RemoteRepositoryName[0..^4]; + cachedLookups = new Dictionary(); } @@ -65,15 +70,15 @@ public GitRemoteFeaturesBase(ILogger logger, Uri remoteUr Models.TestMerge? result; lock (cachedLookups) if (cachedLookups.TryGetValue(parameters, out result)) - Logger.LogTrace("Using cache for test merge #{0}", parameters.Number); + Logger.LogTrace("Using cache for test merge #{testMergeNumber}", parameters.Number); if (result == null) { - Logger.LogTrace("Retrieving metadata for test merge #{0}...", parameters.Number); + Logger.LogTrace("Retrieving metadata for test merge #{testMergeNumber}...", parameters.Number); result = await GetTestMergeImpl(parameters, repositorySettings, cancellationToken); lock (cachedLookups) if (!cachedLookups.TryAdd(parameters, result)) - Logger.LogError("Race condition on adding test merge #{0}!", parameters.Number); + Logger.LogError("Race condition on adding test merge #{testMergeNumber}!", parameters.Number); } return result; From 9a0ec666123aa7825a0091470c3c4ce121d8327d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:08:17 -0500 Subject: [PATCH 674/717] Nullify `GitRemoteFeaturesFactory` Also cleanup logging --- .../Components/Repository/GitRemoteFeaturesFactory.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesFactory.cs b/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesFactory.cs index 2c7c222071c..70694d0b940 100644 --- a/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesFactory.cs +++ b/src/Tgstation.Server.Host/Components/Repository/GitRemoteFeaturesFactory.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Utils.GitHub; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// @@ -80,7 +78,7 @@ public RemoteGitProvider ParseRemoteGitProviderFromOrigin(Uri origin) case "GIT.GITLAB.COM": return RemoteGitProvider.GitLab; default: - logger.LogTrace("Unknown git remote: {0}", origin); + logger.LogDebug("Unknown git remote: {origin}", origin); return RemoteGitProvider.Unknown; } } From 73c309178319c26e5e4f0f53791b80231ef2e5d8 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:08:40 -0500 Subject: [PATCH 675/717] Nullify `ICredentialsProvider` --- .../Components/Repository/ICredentialsProvider.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/ICredentialsProvider.cs b/src/Tgstation.Server.Host/Components/Repository/ICredentialsProvider.cs index d120754a5e1..1324c35320b 100644 --- a/src/Tgstation.Server.Host/Components/Repository/ICredentialsProvider.cs +++ b/src/Tgstation.Server.Host/Components/Repository/ICredentialsProvider.cs @@ -3,8 +3,6 @@ using Tgstation.Server.Host.Jobs; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// @@ -18,7 +16,7 @@ interface ICredentialsProvider /// The optional username to use in the . /// The optional password to use in the . /// A new . - CredentialsHandler GenerateCredentialsHandler(string username, string password); + CredentialsHandler GenerateCredentialsHandler(string? username, string? password); /// /// Rethrow the authentication failure message as a if it is one. From f826a1beafbe9581ba1058f1242f5eea84e61e86 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:08:53 -0500 Subject: [PATCH 676/717] Nullify `IGitRemoteAdditionalInformation` --- .../Components/Repository/IGitRemoteAdditionalInformation.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/IGitRemoteAdditionalInformation.cs b/src/Tgstation.Server.Host/Components/Repository/IGitRemoteAdditionalInformation.cs index a933a85ad18..ffead020f9c 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IGitRemoteAdditionalInformation.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IGitRemoteAdditionalInformation.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// From 4d7991b2ddc319b3ae592e14746c6ab64e95f7ea Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:09:14 -0500 Subject: [PATCH 677/717] Nullify `IGitRemoteFeaturesFactory` --- .../Components/Repository/IGitRemoteFeaturesFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/IGitRemoteFeaturesFactory.cs b/src/Tgstation.Server.Host/Components/Repository/IGitRemoteFeaturesFactory.cs index dd4ee7de3a9..42a55e6285c 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IGitRemoteFeaturesFactory.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IGitRemoteFeaturesFactory.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Api.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// From 992b1710f8e4e99a8654671570c49c528dbd9603 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:09:30 -0500 Subject: [PATCH 678/717] Nullify `ILibGit2Commands` --- .../Components/Repository/ILibGit2Commands.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/ILibGit2Commands.cs b/src/Tgstation.Server.Host/Components/Repository/ILibGit2Commands.cs index e4fc821ec40..6c0ab0da498 100644 --- a/src/Tgstation.Server.Host/Components/Repository/ILibGit2Commands.cs +++ b/src/Tgstation.Server.Host/Components/Repository/ILibGit2Commands.cs @@ -2,8 +2,6 @@ using LibGit2Sharp; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// From 24615ba010fe938f8cc41da4c2be1ad02c26e907 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:09:45 -0500 Subject: [PATCH 679/717] Nullify `ILibGit2RepositoryFactory` --- .../Components/Repository/ILibGit2RepositoryFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/ILibGit2RepositoryFactory.cs b/src/Tgstation.Server.Host/Components/Repository/ILibGit2RepositoryFactory.cs index b69df2783f7..34b8c566691 100644 --- a/src/Tgstation.Server.Host/Components/Repository/ILibGit2RepositoryFactory.cs +++ b/src/Tgstation.Server.Host/Components/Repository/ILibGit2RepositoryFactory.cs @@ -4,8 +4,6 @@ using LibGit2Sharp; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// From 9e761240a3d1cf87bbc165a009348ca081f69b0c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:33:57 -0500 Subject: [PATCH 680/717] Nullify `IRepository` --- .../Components/Instance.cs | 8 ++-- .../Components/Repository/IRepository.cs | 42 +++++++++---------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 38932c52775..0973cd9322a 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -392,8 +392,8 @@ async ValueTask UpdateRevInfo(string currentHead, bool onOrigin, IEnumerable @@ -46,18 +44,18 @@ public interface IRepository : IGitRemoteAdditionalInformation, IDisposable /// Checks out a given . /// /// The sha or reference to checkout. - /// The username used for fetching from submodule repositories. - /// The password used for fetching from submodule repositories. + /// The optional username used for fetching from submodule repositories. + /// The optional password used for fetching from submodule repositories. /// If a submodule update should be attempted after the merge. /// The optional to report progress of the operation. /// The for the operation. /// A representing the running operation. ValueTask CheckoutObject( string committish, - string username, - string password, + string? username, + string? password, bool updateSubmodules, - JobProgressReporter progressReporter, + JobProgressReporter? progressReporter, CancellationToken cancellationToken); /// @@ -66,8 +64,8 @@ ValueTask CheckoutObject( /// The of the pull request. /// The name of the merge committer. /// The e-mail of the merge committer. - /// The username used to fetch from the origin and submodule repositories. - /// The password used to fetch from the origin and submodule repositories. + /// The optional username used to fetch from the origin and submodule repositories. + /// The optional password used to fetch from the origin and submodule repositories. /// If a submodule update should be attempted after the merge. /// The to report progress of the operation. /// The for the operation. @@ -76,8 +74,8 @@ ValueTask AddTestMerge( TestMergeParameters testMergeParameters, string committerName, string committerEmail, - string username, - string password, + string? username, + string? password, bool updateSubmodules, JobProgressReporter progressReporter, CancellationToken cancellationToken); @@ -86,15 +84,15 @@ ValueTask AddTestMerge( /// Fetch commits from the origin repository. /// /// The optional to report progress of the operation. - /// The username to fetch from the origin repository. - /// The password to fetch from the origin repository. + /// The optional username to fetch from the origin repository. + /// The optional password to fetch from the origin repository. /// If any events created should be marked as part of the deployment pipeline. /// The for the operation. /// A representing the running operation. ValueTask FetchOrigin( - JobProgressReporter progressReporter, - string username, - string password, + JobProgressReporter? progressReporter, + string? username, + string? password, bool deploymentPipeline, CancellationToken cancellationToken); @@ -102,16 +100,16 @@ ValueTask FetchOrigin( /// Requires the current HEAD to be a tracked reference. Hard resets the reference to what it tracks on the origin repository. /// /// The to report progress of the operation. - /// The username used for fetching from submodule repositories. - /// The password used for fetching from submodule repositories. + /// The optional username used for fetching from submodule repositories. + /// The optional password used for fetching from submodule repositories. /// If a submodule update should be attempted after the merge. /// If any events created should be marked as part of the deployment pipeline. /// The for the operation. /// A resulting in the SHA of the new HEAD. ValueTask ResetToOrigin( JobProgressReporter progressReporter, - string username, - string password, + string? username, + string? password, bool updateSubmodules, bool deploymentPipeline, CancellationToken cancellationToken); @@ -155,8 +153,8 @@ ValueTask ResetToOrigin( /// A resulting in if commits were pushed to the tracked origin reference, otherwise. ValueTask Sychronize( JobProgressReporter progressReporter, - string username, - string password, + string? username, + string? password, string committerName, string committerEmail, bool synchronizeTrackedBranch, From 9aaad784ac9bc81789338f6df704e19f742905b9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:36:50 -0500 Subject: [PATCH 681/717] Nullify `IRepositoryManager` --- .../Components/Engine/OpenDreamInstaller.cs | 2 +- .../Components/Instance.cs | 3 +++ .../Repository/IRepositoryManager.cs | 20 +++++++++---------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 5244816ead0..a2b74e14457 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -159,7 +159,7 @@ public override async ValueTask DownloadVersion(EngineV Logger.LogTrace("OD repo seems to already exist, attempting load and fetch..."); repo = await repositoryManager.LoadRepository(cancellationToken); - await repo.FetchOrigin( + await repo!.FetchOrigin( progressSection1, null, null, diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 0973cd9322a..0e448251b0e 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -514,6 +514,9 @@ await jobManager.RegisterOperation( Job compileProcessJob; using (var repo = await RepositoryManager.LoadRepository(cancellationToken)) { + if (repo == null) + throw new JobException(Api.Models.ErrorCode.RepoMissing); + var deploySha = repo.Head; if (deploySha == null) { diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs index 090e3cad82c..596301611ac 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManager.cs @@ -4,8 +4,6 @@ using Tgstation.Server.Host.Jobs; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// @@ -28,25 +26,25 @@ public interface IRepositoryManager : IDisposable /// /// The for the operation. /// A resulting in the loaded if it exists, otherwise. - ValueTask LoadRepository(CancellationToken cancellationToken); + ValueTask LoadRepository(CancellationToken cancellationToken); /// /// Clone the repository at . /// /// The of the remote repository to clone. - /// The branch to clone. - /// The username to clone from . - /// The password to clone from . + /// The optional branch to clone. + /// The optional username to clone from . + /// The optional password to clone from . /// The optional for progress of the clone. /// If submodules should be recusively cloned and initialized. /// The for the operation. /// A resulting i the newly cloned , if one already exists. - ValueTask CloneRepository( + ValueTask CloneRepository( Uri url, - string initialBranch, - string username, - string password, - JobProgressReporter progressReporter, + string? initialBranch, + string? username, + string? password, + JobProgressReporter? progressReporter, bool recurseSubmodules, CancellationToken cancellationToken); From 98a0ece919005745cd62e3f5d04f080d0b711b5f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:37:02 -0500 Subject: [PATCH 682/717] Nullify `IRepositoryManagerFactory` --- .../Components/Repository/IRepositoryManagerFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManagerFactory.cs b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManagerFactory.cs index 049ad396dee..0e8c54c70e9 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IRepositoryManagerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IRepositoryManagerFactory.cs @@ -1,8 +1,6 @@ using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// From 4683242bb9861500e15689b4e37656ab4be585cf Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:37:17 -0500 Subject: [PATCH 683/717] Nullify `LibGit2Commands` --- .../Components/Repository/LibGit2Commands.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/LibGit2Commands.cs b/src/Tgstation.Server.Host/Components/Repository/LibGit2Commands.cs index b70dc7b1562..ec5c37a880c 100644 --- a/src/Tgstation.Server.Host/Components/Repository/LibGit2Commands.cs +++ b/src/Tgstation.Server.Host/Components/Repository/LibGit2Commands.cs @@ -3,8 +3,6 @@ using LibGit2Sharp; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// From fdc25c6c37597812f0729de0929a99773b48753c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:37:47 -0500 Subject: [PATCH 684/717] Nullify `LibGit2RepositoryFactory` --- .../Components/Repository/LibGit2RepositoryFactory.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/LibGit2RepositoryFactory.cs b/src/Tgstation.Server.Host/Components/Repository/LibGit2RepositoryFactory.cs index e47d1a553f8..418758ebe73 100644 --- a/src/Tgstation.Server.Host/Components/Repository/LibGit2RepositoryFactory.cs +++ b/src/Tgstation.Server.Host/Components/Repository/LibGit2RepositoryFactory.cs @@ -10,8 +10,6 @@ using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// @@ -82,7 +80,7 @@ public Task Clone(Uri url, CloneOptions cloneOptions, string path, CancellationT TaskScheduler.Current); /// - public CredentialsHandler GenerateCredentialsHandler(string username, string password) => (a, b, supportedCredentialTypes) => + public CredentialsHandler GenerateCredentialsHandler(string? username, string? password) => (a, b, supportedCredentialTypes) => { var hasCreds = username != null; var supportsUserPass = supportedCredentialTypes.HasFlag(SupportedCredentialTypes.UsernamePassword); From 3f758bb560cf379271f4ddcf6e4a298950047006 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:43:42 -0500 Subject: [PATCH 685/717] Correct naming of `Synchronize` function --- src/Tgstation.Server.Host/Components/Instance.cs | 2 +- .../Components/Repository/IRepository.cs | 2 +- .../Components/Repository/Repository.cs | 2 +- .../Components/Repository/RepositoryUpdateService.cs | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs index 0e448251b0e..a8b9a407212 100644 --- a/src/Tgstation.Server.Host/Components/Instance.cs +++ b/src/Tgstation.Server.Host/Components/Instance.cs @@ -452,7 +452,7 @@ await repo.ResetToOrigin( // synch if necessary if (repositorySettings.AutoUpdatesSynchronize!.Value && startSha != repo.Head && (shouldSyncTracked || repositorySettings.PushTestMergeCommits!.Value)) { - var pushedOrigin = await repo.Sychronize( + var pushedOrigin = await repo.Synchronize( NextProgressReporter("Synchronize"), repositorySettings.AccessUser, repositorySettings.AccessToken, diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepository.cs b/src/Tgstation.Server.Host/Components/Repository/IRepository.cs index 795e2646091..65bcd1d61ed 100644 --- a/src/Tgstation.Server.Host/Components/Repository/IRepository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/IRepository.cs @@ -151,7 +151,7 @@ ValueTask ResetToOrigin( /// If any events created should be marked as part of the deployment pipeline. /// The for the operation. /// A resulting in if commits were pushed to the tracked origin reference, otherwise. - ValueTask Sychronize( + ValueTask Synchronize( JobProgressReporter progressReporter, string? username, string? password, diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs index c083dfdde6b..8b440317667 100644 --- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs @@ -613,7 +613,7 @@ await eventConsumer.HandleEvent( } /// - public async ValueTask Sychronize( + public async ValueTask Synchronize( JobProgressReporter progressReporter, string username, string password, diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs index 130718f9e59..4da69c51af0 100644 --- a/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs +++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs @@ -271,7 +271,7 @@ await repo.FetchOrigin( await UpdateRevInfo(); if (fastForward.Value) { - await repo.Sychronize( + await repo.Synchronize( NextProgressReporter("Sychronize"), currentModel.AccessUser, currentModel.AccessToken, @@ -330,7 +330,7 @@ await repo.ResetToOrigin( updateSubmodules, false, cancellationToken); - await repo.Sychronize( + await repo.Synchronize( NextProgressReporter("Synchronize"), currentModel.AccessUser, currentModel.AccessToken, @@ -545,7 +545,7 @@ await databaseContextFactory.UseContext( var currentHead = repo.Head; if (currentModel.PushTestMergeCommits.Value && (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead))) { - await repo.Sychronize( + await repo.Synchronize( NextProgressReporter("Synchronize"), currentModel.AccessUser, currentModel.AccessToken, From 0b3b41dca70a4d8e996a71aa634b4b17cbe43bbd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:44:15 -0500 Subject: [PATCH 686/717] Nullify `TestMergeResult` --- .../Components/Repository/TestMergeResult.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/TestMergeResult.cs b/src/Tgstation.Server.Host/Components/Repository/TestMergeResult.cs index c722590e30f..2505a491d85 100644 --- a/src/Tgstation.Server.Host/Components/Repository/TestMergeResult.cs +++ b/src/Tgstation.Server.Host/Components/Repository/TestMergeResult.cs @@ -2,8 +2,6 @@ using LibGit2Sharp; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// @@ -19,6 +17,6 @@ public sealed class TestMergeResult /// /// List of conflicting file paths relative to the repository root. Only present if is . /// - public IReadOnlyList ConflictingFiles { get; init; } + public IReadOnlyList? ConflictingFiles { get; init; } } } From 695cc4645f6371260f5251e60d6624b1ed6287c0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:44:33 -0500 Subject: [PATCH 687/717] Nullify `RepostoryManagerFactory` --- .../Components/Repository/RepostoryManagerFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/RepostoryManagerFactory.cs b/src/Tgstation.Server.Host/Components/Repository/RepostoryManagerFactory.cs index 140b79f03c3..cba66ff69a4 100644 --- a/src/Tgstation.Server.Host/Components/Repository/RepostoryManagerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Repository/RepostoryManagerFactory.cs @@ -9,8 +9,6 @@ using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// From 874f16da4b56045f9ed0010cdc20d69b76249d65 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:53:19 -0500 Subject: [PATCH 688/717] Nullify `RepositoryUpdateService` --- .../Repository/RepositoryUpdateService.cs | 137 +++++++++--------- 1 file changed, 72 insertions(+), 65 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs index 4da69c51af0..a7aca78c4b8 100644 --- a/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs +++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs @@ -15,8 +15,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Models; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// @@ -87,16 +85,18 @@ public static async ValueTask LoadRevisionInformation( IDatabaseContext databaseContext, ILogger logger, Models.Instance instance, - string lastOriginCommitSha, - Action revInfoSink, + string? lastOriginCommitSha, + Action? revInfoSink, CancellationToken cancellationToken) { var repoSha = repository.Head; IQueryable ApplyQuery(IQueryable query) => query - .Where(x => x.CommitSha == repoSha && x.Instance.Id == instance.Id) + .Where(x => x.CommitSha == repoSha && x.InstanceId == instance.Id) .Include(x => x.CompileJobs) - .Include(x => x.ActiveTestMerges).ThenInclude(x => x.TestMerge).ThenInclude(x => x.MergedBy); + .Include(x => x.ActiveTestMerges!) + .ThenInclude(x => x.TestMerge) + .ThenInclude(x => x.MergedBy); var revisionInfo = await ApplyQuery(databaseContext.RevisionInformations).FirstOrDefaultAsync(cancellationToken); @@ -105,7 +105,7 @@ public static async ValueTask LoadRevisionInformation( revisionInfo = databaseContext .RevisionInformations .Local - .Where(x => x.CommitSha == repoSha && x.Instance.Id == instance.Id) + .Where(x => x.CommitSha == repoSha && x.InstanceId == instance.Id) .FirstOrDefault(); var needsDbUpdate = revisionInfo == default; @@ -125,7 +125,7 @@ public static async ValueTask LoadRevisionInformation( databaseContext.RevisionInformations.Add(revisionInfo); } - revisionInfo.OriginCommitSha ??= lastOriginCommitSha; + revisionInfo!.OriginCommitSha ??= lastOriginCommitSha; if (revisionInfo.OriginCommitSha == null) { revisionInfo.OriginCommitSha = repoSha; @@ -147,13 +147,15 @@ public static async ValueTask LoadRevisionInformation( /// A representing the running operation. #pragma warning disable CA1502, CA1506 // TODO: Decomplexify public async ValueTask RepositoryUpdateJob( - IInstanceCore instance, + IInstanceCore? instance, IDatabaseContextFactory databaseContextFactory, Job job, JobProgressReporter progressReporter, CancellationToken cancellationToken) #pragma warning restore CA1502, CA1506 { + ArgumentNullException.ThrowIfNull(instance); + _ = job; // shuts up an IDE warning var repoManager = instance.RepositoryManager; @@ -162,23 +164,23 @@ public async ValueTask RepositoryUpdateJob( var startReference = repo.Reference; var startSha = repo.Head; - string postUpdateSha = null; + string? postUpdateSha = null; var newTestMerges = model.NewTestMerges != null && model.NewTestMerges.Count > 0; if (newTestMerges && repo.RemoteGitProvider == RemoteGitProvider.Unknown) throw new JobException(ErrorCode.RepoUnsupportedTestMergeRemote); - var committerName = currentModel.ShowTestMergeCommitters.Value + var committerName = (currentModel.ShowTestMergeCommitters!.Value ? initiatingUser.Name - : currentModel.CommitterName; + : currentModel.CommitterName)!; var hardResettingToOriginReference = model.UpdateFromOrigin == true && model.Reference != null; var numSteps = (model.NewTestMerges?.Count ?? 0) + (model.UpdateFromOrigin == true ? 1 : 0) + (!modelHasShaOrReference ? 2 : (hardResettingToOriginReference ? 3 : 1)); var progressFactor = 1.0 / numSteps; - JobProgressReporter NextProgressReporter(string stage) + JobProgressReporter NextProgressReporter(string? stage) { return progressReporter.CreateSection(stage, progressFactor); } @@ -186,19 +188,19 @@ JobProgressReporter NextProgressReporter(string stage) progressReporter.ReportProgress(0); // get a base line for where we are - Models.RevisionInformation lastRevisionInfo = null; + Models.RevisionInformation? lastRevisionInfo = null; var attachedInstance = new Models.Instance { Id = instanceId, }; - ValueTask CallLoadRevInfo(Models.TestMerge testMergeToAdd = null, string lastOriginCommitSha = null) => databaseContextFactory + ValueTask CallLoadRevInfo(Models.TestMerge? testMergeToAdd = null, string? lastOriginCommitSha = null) => databaseContextFactory .UseContext( async databaseContext => { databaseContext.Instances.Attach(attachedInstance); - var previousRevInfo = lastRevisionInfo; + var previousRevInfo = lastRevisionInfo!; var needsUpdate = await LoadRevisionInformation( repo, databaseContext, @@ -225,10 +227,11 @@ ValueTask CallLoadRevInfo(Models.TestMerge testMergeToAdd = null, string lastOri testMergeToAdd.MergedBy = mergedBy; testMergeToAdd.MergedAt = DateTimeOffset.UtcNow; - foreach (var activeTestMerge in previousRevInfo.ActiveTestMerges) - lastRevisionInfo.ActiveTestMerges.Add(activeTestMerge); + var activeTestMerges = lastRevisionInfo!.ActiveTestMerges!; + foreach (var activeTestMerge in previousRevInfo.ActiveTestMerges!) + activeTestMerges.Add(activeTestMerge); - lastRevisionInfo.ActiveTestMerges.Add(new RevInfoTestMerge(testMergeToAdd, lastRevisionInfo)); + activeTestMerges.Add(new RevInfoTestMerge(testMergeToAdd, lastRevisionInfo)); lastRevisionInfo.PrimaryTestMerge = testMergeToAdd; needsUpdate = true; @@ -241,7 +244,7 @@ ValueTask CallLoadRevInfo(Models.TestMerge testMergeToAdd = null, string lastOri await CallLoadRevInfo(); // apply new rev info, tracking applied test merges - ValueTask UpdateRevInfo(Models.TestMerge testMergeToAdd = null) => CallLoadRevInfo(testMergeToAdd, lastRevisionInfo.OriginCommitSha); + ValueTask UpdateRevInfo(Models.TestMerge? testMergeToAdd = null) => CallLoadRevInfo(testMergeToAdd, lastRevisionInfo!.OriginCommitSha); try { @@ -262,12 +265,12 @@ await repo.FetchOrigin( var fastForward = await repo.MergeOrigin( NextProgressReporter("Merge Origin"), committerName, - currentModel.CommitterEmail, + currentModel.CommitterEmail!, false, cancellationToken); if (!fastForward.HasValue) throw new JobException(ErrorCode.RepoMergeConflict); - lastRevisionInfo.OriginCommitSha = await repo.GetOriginSha(cancellationToken); + lastRevisionInfo!.OriginCommitSha = await repo.GetOriginSha(cancellationToken); await UpdateRevInfo(); if (fastForward.Value) { @@ -275,8 +278,8 @@ await repo.Synchronize( NextProgressReporter("Sychronize"), currentModel.AccessUser, currentModel.AccessToken, - currentModel.CommitterName, - currentModel.CommitterEmail, + currentModel.CommitterName!, + currentModel.CommitterEmail!, true, false, cancellationToken); @@ -287,7 +290,7 @@ await repo.Synchronize( } } - var updateSubmodules = currentModel.UpdateSubmodules.Value; + var updateSubmodules = currentModel.UpdateSubmodules!.Value; // checkout/hard reset if (modelHasShaOrReference) @@ -301,7 +304,7 @@ await repo.Synchronize( if (validCheckoutSha || validCheckoutReference) { - var committish = model.CheckoutSha ?? model.Reference; + var committish = model.CheckoutSha ?? model.Reference!; var isSha = await repo.IsSha(committish, cancellationToken); if ((isSha && model.Reference != null) || (!isSha && model.CheckoutSha != null)) @@ -334,8 +337,8 @@ await repo.Synchronize( NextProgressReporter("Synchronize"), currentModel.AccessUser, currentModel.AccessToken, - currentModel.CommitterName, - currentModel.CommitterEmail, + currentModel.CommitterName!, + currentModel.CommitterEmail!, true, false, cancellationToken); @@ -343,7 +346,7 @@ await repo.Synchronize( // repo head is on origin so force this // will update the db if necessary - lastRevisionInfo.OriginCommitSha = repo.Head; + lastRevisionInfo!.OriginCommitSha = repo.Head; } } @@ -354,19 +357,20 @@ await repo.Synchronize( throw new JobException(ErrorCode.RepoTestMergeInvalidRemote); // bit of sanitization - foreach (var newTestMergeWithoutTargetCommitSha in model.NewTestMerges.Where(x => String.IsNullOrWhiteSpace(x.TargetCommitSha))) + var newTestMergeModels = model.NewTestMerges!; + foreach (var newTestMergeWithoutTargetCommitSha in newTestMergeModels.Where(x => String.IsNullOrWhiteSpace(x.TargetCommitSha))) newTestMergeWithoutTargetCommitSha.TargetCommitSha = null; var repoOwner = repo.RemoteRepositoryOwner; var repoName = repo.RemoteRepositoryName; // optimization: if we've already merged these exact same commits in this fashion before, just find the rev info for it and check it out - Models.RevisionInformation revInfoWereLookingFor = null; + Models.RevisionInformation? revInfoWereLookingFor = null; bool needToApplyRemainingPrs = true; - if (lastRevisionInfo.OriginCommitSha == lastRevisionInfo.CommitSha) + if (lastRevisionInfo!.OriginCommitSha == lastRevisionInfo.CommitSha) { bool cantSearch = false; - foreach (var newTestMerge in model.NewTestMerges) + foreach (var newTestMerge in newTestMergeModels) { if (newTestMerge.TargetCommitSha != null) #pragma warning disable CA1308 // Normalize strings to uppercase @@ -390,56 +394,58 @@ await repo.Synchronize( if (!cantSearch) { - List dbPull = null; + List? dbPull = null; await databaseContextFactory.UseContext( async databaseContext => dbPull = await databaseContext.RevisionInformations .AsQueryable() - .Where(x => x.Instance.Id == instanceId - && x.OriginCommitSha == lastRevisionInfo.OriginCommitSha - && x.ActiveTestMerges.Count <= model.NewTestMerges.Count - && x.ActiveTestMerges.Count > 0) - .Include(x => x.ActiveTestMerges) - .ThenInclude(x => x.TestMerge) + .Where(x => x.InstanceId == instanceId + && x.OriginCommitSha == lastRevisionInfo.OriginCommitSha + && x.ActiveTestMerges!.Count <= newTestMergeModels.Count + && x.ActiveTestMerges!.Count > 0) + .Include(x => x.ActiveTestMerges!) + .ThenInclude(x => x.TestMerge) .ToListAsync(cancellationToken)); // split here cause this bit has to be done locally - revInfoWereLookingFor = dbPull - .Where(x => x.ActiveTestMerges.Count == model.NewTestMerges.Count - && x.ActiveTestMerges.Select(y => y.TestMerge) - .All(y => model.NewTestMerges.Any(z => - y.Number == z.Number - && y.TargetCommitSha.StartsWith(z.TargetCommitSha, StringComparison.Ordinal) - && (y.Comment?.Trim().ToUpperInvariant() == z.Comment?.Trim().ToUpperInvariant() || z.Comment == null)))) + revInfoWereLookingFor = dbPull! + .Where(x => x.ActiveTestMerges!.Count == newTestMergeModels.Count + && x.ActiveTestMerges + .Select(y => y.TestMerge) + .All(y => newTestMergeModels + .Any(z => + y.Number == z.Number + && y.TargetCommitSha!.StartsWith(z.TargetCommitSha!, StringComparison.Ordinal) + && (y.Comment?.Trim().ToUpperInvariant() == z.Comment?.Trim().ToUpperInvariant() || z.Comment == null)))) .FirstOrDefault(); - if (revInfoWereLookingFor == default && model.NewTestMerges.Count > 1) + if (revInfoWereLookingFor == default && newTestMergeModels.Count > 1) { // okay try to add at least SOME prs we've seen before - var listedNewTestMerges = model.NewTestMerges.ToList(); + var listedNewTestMerges = newTestMergeModels.ToList(); var appliedTestMergeIds = new List(); - Models.RevisionInformation lastGoodRevInfo = null; + Models.RevisionInformation? lastGoodRevInfo = null; do { foreach (var newTestMergeParameters in listedNewTestMerges) { - revInfoWereLookingFor = dbPull + revInfoWereLookingFor = dbPull! .Where(testRevInfo => { if (testRevInfo.PrimaryTestMerge == null) return false; - var testMergeMatch = model.NewTestMerges.Any(testTestMerge => + var testMergeMatch = newTestMergeModels.Any(testTestMerge => { var numberMatch = testRevInfo.PrimaryTestMerge.Number == testTestMerge.Number; if (!numberMatch) return false; - var shaMatch = testRevInfo.PrimaryTestMerge.TargetCommitSha.StartsWith( - testTestMerge.TargetCommitSha, + var shaMatch = testRevInfo.PrimaryTestMerge.TargetCommitSha!.StartsWith( + testTestMerge.TargetCommitSha!, StringComparison.Ordinal); if (!shaMatch) return false; @@ -452,7 +458,7 @@ await databaseContextFactory.UseContext( return false; var previousTestMergesMatch = testRevInfo - .ActiveTestMerges + .ActiveTestMerges! .Select(previousRevInfoTestMerge => previousRevInfoTestMerge.TestMerge) .All(previousTestMerge => appliedTestMergeIds.Contains(previousTestMerge.Id)); @@ -463,7 +469,7 @@ await databaseContextFactory.UseContext( if (revInfoWereLookingFor != null) { lastGoodRevInfo = revInfoWereLookingFor; - appliedTestMergeIds.Add(revInfoWereLookingFor.PrimaryTestMerge.Id); + appliedTestMergeIds.Add(revInfoWereLookingFor.PrimaryTestMerge!.Id); listedNewTestMerges.Remove(newTestMergeParameters); break; } @@ -484,16 +490,17 @@ await databaseContextFactory.UseContext( if (revInfoWereLookingFor != null) { // goteem - logger.LogDebug("Reusing existing SHA {sha}...", revInfoWereLookingFor.CommitSha); - await repo.ResetToSha(revInfoWereLookingFor.CommitSha, NextProgressReporter($"Reset to {revInfoWereLookingFor.CommitSha[..7]}"), cancellationToken); + var commitSha = revInfoWereLookingFor.CommitSha!; + logger.LogDebug("Reusing existing SHA {sha}...", commitSha); + await repo.ResetToSha(commitSha, NextProgressReporter($"Reset to {commitSha[..7]}"), cancellationToken); lastRevisionInfo = revInfoWereLookingFor; } if (needToApplyRemainingPrs) { - foreach (var newTestMerge in model.NewTestMerges) + foreach (var newTestMerge in newTestMergeModels) { - if (lastRevisionInfo.ActiveTestMerges.Any(x => x.TestMerge.Number == newTestMerge.Number)) + if (lastRevisionInfo.ActiveTestMerges!.Any(x => x.TestMerge.Number == newTestMerge.Number)) throw new JobException(ErrorCode.RepoDuplicateTestMerge); var fullTestMergeTask = repo.GetTestMerge(newTestMerge, currentModel, cancellationToken); @@ -501,7 +508,7 @@ await databaseContextFactory.UseContext( var mergeResult = await repo.AddTestMerge( newTestMerge, committerName, - currentModel.CommitterEmail, + currentModel.CommitterEmail!, currentModel.AccessUser, currentModel.AccessToken, updateSubmodules, @@ -512,7 +519,7 @@ await databaseContextFactory.UseContext( throw new JobException( ErrorCode.RepoTestMergeConflict, new JobException( - $"Test Merge #{newTestMerge.Number} at {newTestMerge.TargetCommitSha[..7]} conflicted! Conflicting files:{Environment.NewLine}{String.Join(Environment.NewLine, mergeResult.ConflictingFiles.Select(file => $"\t- /{file}"))}")); + $"Test Merge #{newTestMerge.Number} at {newTestMerge.TargetCommitSha![..7]} conflicted! Conflicting files:{Environment.NewLine}{String.Join(Environment.NewLine, mergeResult.ConflictingFiles!.Select(file => $"\t- /{file}"))}")); Models.TestMerge fullTestMerge; try @@ -543,14 +550,14 @@ await databaseContextFactory.UseContext( } var currentHead = repo.Head; - if (currentModel.PushTestMergeCommits.Value && (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead))) + if (currentModel.PushTestMergeCommits!.Value && (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead))) { await repo.Synchronize( NextProgressReporter("Synchronize"), currentModel.AccessUser, currentModel.AccessToken, - currentModel.CommitterName, - currentModel.CommitterEmail, + currentModel.CommitterName!, + currentModel.CommitterEmail!, false, false, cancellationToken); From 0a3de43ccce9c85b5a993c051a45813896ee17aa Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:54:30 -0500 Subject: [PATCH 689/717] Nullify `RepositoryManager` --- .../Components/Repository/RepositoryManager.cs | 14 ++++++-------- .../Extensions/FetchOptionsExtensions.cs | 4 ++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs index d733b1e5061..727d171e4e6 100644 --- a/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs +++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryManager.cs @@ -14,8 +14,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// @@ -120,12 +118,12 @@ public void Dispose() } /// - public async ValueTask CloneRepository( + public async ValueTask CloneRepository( Uri url, - string initialBranch, - string username, - string password, - JobProgressReporter progressReporter, + string? initialBranch, + string? username, + string? password, + JobProgressReporter? progressReporter, bool recurseSubmodules, CancellationToken cancellationToken) { @@ -210,7 +208,7 @@ await repositoryFactory.Clone( } /// - public async ValueTask LoadRepository(CancellationToken cancellationToken) + public async ValueTask LoadRepository(CancellationToken cancellationToken) { logger.LogTrace("Begin LoadRepository..."); lock (semaphore) diff --git a/src/Tgstation.Server.Host/Extensions/FetchOptionsExtensions.cs b/src/Tgstation.Server.Host/Extensions/FetchOptionsExtensions.cs index e1b47d644a5..6d71a68edf8 100644 --- a/src/Tgstation.Server.Host/Extensions/FetchOptionsExtensions.cs +++ b/src/Tgstation.Server.Host/Extensions/FetchOptionsExtensions.cs @@ -27,7 +27,7 @@ static class FetchOptionsExtensions public static FetchOptions Hydrate( this FetchOptions fetchOptions, ILogger logger, - JobProgressReporter progressReporter, + JobProgressReporter? progressReporter, CredentialsHandler credentialsHandler, CancellationToken cancellationToken) { @@ -63,7 +63,7 @@ public static FetchOptions Hydrate( /// The optional of the operation. /// The for the operation. /// A new based on . - static TransferProgressHandler TransferProgressHandler(ILogger logger, JobProgressReporter progressReporter, CancellationToken cancellationToken) => transferProgress => + static TransferProgressHandler TransferProgressHandler(ILogger logger, JobProgressReporter? progressReporter, CancellationToken cancellationToken) => transferProgress => { double? percentage; var totalObjectsToProcess = transferProgress.TotalObjects * 2; From 4a950aad630397310c59b4c7014661f3301788f2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 11:57:04 -0500 Subject: [PATCH 690/717] Nullify `Repository` --- .../Components/Repository/Repository.cs | 64 +++++++++---------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs index 8b440317667..5518c1a44d3 100644 --- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs +++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs @@ -19,8 +19,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Repository { /// @@ -56,10 +54,10 @@ sealed class Repository : DisposeInvoker, IRepository public RemoteGitProvider? RemoteGitProvider => gitRemoteFeatures.RemoteGitProvider; /// - public string RemoteRepositoryOwner => gitRemoteFeatures.RemoteRepositoryOwner; + public string? RemoteRepositoryOwner => gitRemoteFeatures.RemoteRepositoryOwner; /// - public string RemoteRepositoryName => gitRemoteFeatures.RemoteRepositoryName; + public string? RemoteRepositoryName => gitRemoteFeatures.RemoteRepositoryName; /// public bool Tracking => Reference != null && libGitRepo.Head.IsTracking; @@ -164,8 +162,8 @@ public async ValueTask AddTestMerge( TestMergeParameters testMergeParameters, string committerName, string committerEmail, - string username, - string password, + string? username, + string? password, bool updateSubmodules, JobProgressReporter progressReporter, CancellationToken cancellationToken) @@ -204,12 +202,12 @@ public async ValueTask AddTestMerge( var originalCommit = libGitRepo.Head; - MergeResult result = null; + MergeResult? result = null; var progressFactor = 1.0 / (updateSubmodules ? 3 : 2); var sig = new Signature(new Identity(committerName, committerEmail), DateTimeOffset.UtcNow); - List conflictedPaths = null; + List? conflictedPaths = null; await Task.Factory.StartNew( () => { @@ -293,17 +291,17 @@ await Task.Factory.StartNew( DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current); - if (result.Status == MergeStatus.Conflicts) + if (result!.Status == MergeStatus.Conflicts) { var arguments = new List { originalCommit.Tip.Sha, - testMergeParameters.TargetCommitSha, + testMergeParameters.TargetCommitSha!, originalCommit.FriendlyName ?? UnknownReference, testMergeBranchName, }; - arguments.AddRange(conflictedPaths); + arguments.AddRange(conflictedPaths!); await eventConsumer.HandleEvent( EventType.RepoMergeConflict, @@ -342,10 +340,10 @@ await UpdateSubmodules( await eventConsumer.HandleEvent( EventType.RepoAddTestMerge, - new List + new List { testMergeParameters.Number.ToString(CultureInfo.InvariantCulture), - testMergeParameters.TargetCommitSha, + testMergeParameters.TargetCommitSha!, testMergeParameters.Comment, }, false, @@ -361,10 +359,10 @@ await eventConsumer.HandleEvent( /// public async ValueTask CheckoutObject( string committish, - string username, - string password, + string? username, + string? password, bool updateSubmodules, - JobProgressReporter progressReporter, + JobProgressReporter? progressReporter, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(committish); @@ -395,9 +393,9 @@ await UpdateSubmodules( /// public async ValueTask FetchOrigin( - JobProgressReporter progressReporter, - string username, - string password, + JobProgressReporter? progressReporter, + string? username, + string? password, bool deploymentPipeline, CancellationToken cancellationToken) { @@ -445,8 +443,8 @@ await Task.Factory.StartNew( /// public async ValueTask ResetToOrigin( JobProgressReporter progressReporter, - string username, - string password, + string? username, + string? password, bool updateSubmodules, bool deploymentPipeline, CancellationToken cancellationToken) @@ -543,8 +541,8 @@ public Task GetOriginSha(CancellationToken cancellationToken) => Task.Fa { ArgumentNullException.ThrowIfNull(progressReporter); - MergeResult result = null; - Branch trackedBranch = null; + MergeResult? result = null; + Branch? trackedBranch = null; var oldHead = libGitRepo.Head; var oldTip = oldHead.Tip; @@ -593,14 +591,14 @@ await Task.Factory.StartNew( DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current); - if (result.Status == MergeStatus.Conflicts) + if (result!.Status == MergeStatus.Conflicts) { await eventConsumer.HandleEvent( EventType.RepoMergeConflict, new List { oldTip.Sha, - trackedBranch.Tip.Sha, + trackedBranch!.Tip.Sha, oldHead.FriendlyName ?? UnknownReference, trackedBranch.FriendlyName, }, @@ -615,8 +613,8 @@ await eventConsumer.HandleEvent( /// public async ValueTask Synchronize( JobProgressReporter progressReporter, - string username, - string password, + string? username, + string? password, string committerName, string committerEmail, bool synchronizeTrackedBranch, @@ -858,7 +856,7 @@ protected override void DisposeImpl() /// The committish to checkout. /// The optional for the operation. /// The for the operation. - void RawCheckout(string committish, JobProgressReporter progressReporter, CancellationToken cancellationToken) + void RawCheckout(string committish, JobProgressReporter? progressReporter, CancellationToken cancellationToken) { logger.LogTrace("Checkout: {committish}", committish); @@ -993,15 +991,15 @@ PushOptions GeneratePushOptions(JobProgressReporter progressReporter, string use /// Recusively update all s in the . /// /// Optional of the operation. - /// The username for the . - /// The password for the . + /// The optional username for the . + /// The optional password for the . /// If any events created should be marked as part of the deployment pipeline. /// The for the operation. /// A representing the running operation. async ValueTask UpdateSubmodules( - JobProgressReporter progressReporter, - string username, - string password, + JobProgressReporter? progressReporter, + string? username, + string? password, bool deploymentPipeline, CancellationToken cancellationToken) { From 46c4114c24ea79472ddc15245143433af8abbdf0 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 12:05:22 -0500 Subject: [PATCH 691/717] Nullify `CombinedTopicResponse` --- .../Components/Session/CombinedTopicResponse.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/CombinedTopicResponse.cs b/src/Tgstation.Server.Host/Components/Session/CombinedTopicResponse.cs index 2b7a09b1749..d98fa10efd5 100644 --- a/src/Tgstation.Server.Host/Components/Session/CombinedTopicResponse.cs +++ b/src/Tgstation.Server.Host/Components/Session/CombinedTopicResponse.cs @@ -2,8 +2,6 @@ using Tgstation.Server.Host.Components.Interop.Topic; -#nullable disable - namespace Tgstation.Server.Host.Components.Session { /// @@ -19,14 +17,14 @@ sealed class CombinedTopicResponse /// /// The interop , if any. /// - public TopicResponse InteropResponse { get; } + public TopicResponse? InteropResponse { get; } /// /// Initializes a new instance of the class. /// /// The value of . /// The optional value of . - public CombinedTopicResponse(global::Byond.TopicSender.TopicResponse byondTopicResponse, TopicResponse interopResponse) + public CombinedTopicResponse(global::Byond.TopicSender.TopicResponse byondTopicResponse, TopicResponse? interopResponse) { ByondTopicResponse = byondTopicResponse ?? throw new ArgumentNullException(nameof(byondTopicResponse)); InteropResponse = interopResponse; From 16d50692fa3808e68414bf528774aad55b243a01 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 12:06:45 -0500 Subject: [PATCH 692/717] Nullify `ISessionController` --- .../Components/Session/CombinedTopicResponse.cs | 8 ++++---- .../Components/Session/ISessionController.cs | 6 ++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/CombinedTopicResponse.cs b/src/Tgstation.Server.Host/Components/Session/CombinedTopicResponse.cs index d98fa10efd5..ad22b6204b7 100644 --- a/src/Tgstation.Server.Host/Components/Session/CombinedTopicResponse.cs +++ b/src/Tgstation.Server.Host/Components/Session/CombinedTopicResponse.cs @@ -5,14 +5,14 @@ namespace Tgstation.Server.Host.Components.Session { /// - /// Combines a with a . + /// Combines a with a . /// sealed class CombinedTopicResponse { /// - /// The raw . + /// The raw . /// - public global::Byond.TopicSender.TopicResponse ByondTopicResponse { get; } + public Byond.TopicSender.TopicResponse ByondTopicResponse { get; } /// /// The interop , if any. @@ -24,7 +24,7 @@ sealed class CombinedTopicResponse /// /// The value of . /// The optional value of . - public CombinedTopicResponse(global::Byond.TopicSender.TopicResponse byondTopicResponse, TopicResponse? interopResponse) + public CombinedTopicResponse(Byond.TopicSender.TopicResponse byondTopicResponse, TopicResponse? interopResponse) { ByondTopicResponse = byondTopicResponse ?? throw new ArgumentNullException(nameof(byondTopicResponse)); InteropResponse = interopResponse; diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs index d42190c78f6..ccdaa448c4c 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Host.Components.Interop.Topic; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Components.Session { /// @@ -34,7 +32,7 @@ interface ISessionController : IProcessBase, IRenameNotifyee, IAsyncDisposable /// /// The DMAPI . /// - Version DMApiVersion { get; } + Version? DMApiVersion { get; } /// /// Gets the associated with the . @@ -98,7 +96,7 @@ interface ISessionController : IProcessBase, IRenameNotifyee, IAsyncDisposable /// The to send. /// The for the operation. /// A resulting in the of /world/Topic(). - ValueTask SendCommand(TopicParameters parameters, CancellationToken cancellationToken); + ValueTask SendCommand(TopicParameters parameters, CancellationToken cancellationToken); /// /// Attempts to change the current to . From b81ecda0754fc89a05424d5e64782590e21dc131 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 12:07:10 -0500 Subject: [PATCH 693/717] Nullify `ISessionControllerFactory` --- .../Components/Session/ISessionControllerFactory.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs index 34f58c8cc07..c6d1a634ff2 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Components.Engine; -#nullable disable - namespace Tgstation.Server.Host.Components.Session { /// @@ -18,14 +16,14 @@ interface ISessionControllerFactory /// Create a from a freshly launch DreamDaemon instance. /// /// The to use. - /// The current if any. + /// The current . if any. /// The to use. will be updated with the minumum required security level for the launch. /// If the should only validate the DMAPI then exit. /// The for the operation. /// A resulting in a new . ValueTask LaunchNew( IDmbProvider dmbProvider, - IEngineExecutableLock currentByondLock, + IEngineExecutableLock? currentByondLock, DreamDaemonLaunchParameters launchParameters, bool apiValidate, CancellationToken cancellationToken); From dd1588f8841b8607226a76220c299ffe326b1569 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 12:07:30 -0500 Subject: [PATCH 694/717] Nullify `ISessionPersistor` --- .../Components/Session/ISessionPersistor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs index 597208530ee..9d3806c3177 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionPersistor.cs @@ -1,8 +1,6 @@ using System.Threading; using System.Threading.Tasks; -#nullable disable - namespace Tgstation.Server.Host.Components.Session { /// @@ -31,7 +29,7 @@ public interface ISessionPersistor /// /// The for the operation. /// A resulting in the stored if any. - ValueTask Load(CancellationToken cancellationToken); + ValueTask Load(CancellationToken cancellationToken); /// /// Clear any stored . From 835ec189c6fda8e2ac5bca6d978c96962e99b161 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 12:07:43 -0500 Subject: [PATCH 695/717] Nullify `ITopicClientFactory` --- .../Components/Session/ITopicClientFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/ITopicClientFactory.cs b/src/Tgstation.Server.Host/Components/Session/ITopicClientFactory.cs index 7f60ace9d0c..c4be5235a1d 100644 --- a/src/Tgstation.Server.Host/Components/Session/ITopicClientFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/ITopicClientFactory.cs @@ -2,8 +2,6 @@ using Byond.TopicSender; -#nullable disable - namespace Tgstation.Server.Host.Components.Session { /// From f8e4af3be5e96fc3beee4fd49defbdd576d3b854 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 12:08:12 -0500 Subject: [PATCH 696/717] Nullify `LaunchResult` --- .../Components/Session/LaunchResult.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/LaunchResult.cs b/src/Tgstation.Server.Host/Components/Session/LaunchResult.cs index de536ce83e6..eb44b6e55f7 100644 --- a/src/Tgstation.Server.Host/Components/Session/LaunchResult.cs +++ b/src/Tgstation.Server.Host/Components/Session/LaunchResult.cs @@ -1,8 +1,6 @@ using System; using System.Globalization; -#nullable disable - namespace Tgstation.Server.Host.Components.Session { /// @@ -13,12 +11,12 @@ public sealed class LaunchResult /// /// The time it took for to return or the initial bridge request to process. If the startup timed out. /// - public TimeSpan? StartupTime { get; set; } + public TimeSpan? StartupTime { get; init; } /// /// The if it exited. /// - public int? ExitCode { get; set; } + public int? ExitCode { get; init; } /// public override string ToString() => String.Format(CultureInfo.InvariantCulture, "Exit Code: {0}, Time {1}ms", ExitCode, StartupTime?.TotalMilliseconds); From e655767d31a2e6ce3bf5f47ad0a7db4175efe82f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 20:55:21 -0500 Subject: [PATCH 697/717] Use `FrozenDictionary` where appropriate --- .../Components/Engine/DelegatingEngineInstaller.cs | 8 ++++---- src/Tgstation.Server.Host/Core/Application.cs | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs index c7c5363a955..1157dff565a 100644 --- a/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/DelegatingEngineInstaller.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; +using System.Collections.Frozen; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -15,15 +15,15 @@ namespace Tgstation.Server.Host.Components.Engine sealed class DelegatingEngineInstaller : IEngineInstaller { /// - /// The mapping s to their appropriate . + /// The mapping s to their appropriate . /// - readonly IReadOnlyDictionary delegatedInstallers; + readonly FrozenDictionary delegatedInstallers; /// /// Initializes a new instance of the class. /// /// The value of . - public DelegatingEngineInstaller(IReadOnlyDictionary delegatedInstallers) + public DelegatingEngineInstaller(FrozenDictionary delegatedInstallers) { this.delegatedInstallers = delegatedInstallers ?? throw new ArgumentNullException(nameof(delegatedInstallers)); } diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 202b098d7c8..3b80d9da389 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Frozen; using System.Collections.Generic; using System.Globalization; using System.Threading.Tasks; @@ -380,12 +381,13 @@ void AddTypedContext() openDreamRepositoryDirectory), new NoopEventConsumer())); - services.AddSingleton>( + services.AddSingleton( serviceProvider => new Dictionary { { EngineType.Byond, serviceProvider.GetRequiredService() }, { EngineType.OpenDream, serviceProvider.GetRequiredService() }, - }); + } + .ToFrozenDictionary()); services.AddSingleton(); if (postSetupServices.InternalConfiguration.UsingSystemD) From 6a9e7358a5b3d34474712b8a8687fe219e4eb527 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 20:56:44 -0500 Subject: [PATCH 698/717] Switch to named logging placeholder --- tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs b/tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs index dec859f6afb..fe6746cb73f 100644 --- a/tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs +++ b/tests/Tgstation.Server.Tests/Live/DummyChatProviderFactory.cs @@ -55,7 +55,7 @@ public DummyChatProviderFactory(IJobManager jobManager, ICryptographySuite crypt ? new Random().Next() : 22475; - logger.LogInformation("Random seed: {0}", randomSeed); + logger.LogInformation("Random seed: {randomSeed}", randomSeed); var baseRng = new Random(randomSeed); seededRng = new Dictionary{ From e1f9d1e59d4d49e18aa02d4ac496da53be69183c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 20:58:50 -0500 Subject: [PATCH 699/717] Nullify `ReattachInformation` --- .../Components/Session/ReattachInformation.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/ReattachInformation.cs b/src/Tgstation.Server.Host/Components/Session/ReattachInformation.cs index 31aa0834b7b..df2ce141d45 100644 --- a/src/Tgstation.Server.Host/Components/Session/ReattachInformation.cs +++ b/src/Tgstation.Server.Host/Components/Session/ReattachInformation.cs @@ -5,8 +5,6 @@ using Tgstation.Server.Host.Models; using Tgstation.Server.Host.System; -#nullable disable - namespace Tgstation.Server.Host.Components.Session { /// @@ -22,12 +20,12 @@ public sealed class ReattachInformation : ReattachInformationBase /// /// The initially used to launch DreamDaemon. Should be a different than . Should not be set if persisting the initial isn't necessary. /// - public IDmbProvider InitialDmb { get; set; } + public IDmbProvider? InitialDmb { get; set; } /// /// The for the DMAPI. /// - public RuntimeInformation RuntimeInformation { get; private set; } + public RuntimeInformation? RuntimeInformation { get; private set; } /// /// The which indicates when topic requests should timeout. @@ -49,7 +47,7 @@ public sealed class ReattachInformation : ReattachInformationBase public ReattachInformation( Models.ReattachInformation copy, IDmbProvider dmb, - IDmbProvider initialDmb, + IDmbProvider? initialDmb, TimeSpan topicRequestTimeout) : base(copy) { From 47ac4229ae3a81d6b1c680f0e7f4221b8ad50165 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 21:17:35 -0500 Subject: [PATCH 700/717] Nullify `SessionController` --- .../Components/Interop/Chunker.cs | 14 +++-- .../Components/Session/SessionController.cs | 60 ++++++++++--------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Interop/Chunker.cs b/src/Tgstation.Server.Host/Components/Interop/Chunker.cs index c95d97b9e6f..e13cfd00bac 100644 --- a/src/Tgstation.Server.Host/Components/Interop/Chunker.cs +++ b/src/Tgstation.Server.Host/Components/Interop/Chunker.cs @@ -64,11 +64,12 @@ protected Chunker(ILogger logger) /// The . /// The for the operation. /// A resulting in the for the chunked request. - protected async ValueTask ProcessChunk( - Func> completionCallback, - Func chunkErrorCallback, - ChunkData chunk, + protected async ValueTask ProcessChunk( + Func> completionCallback, + Func chunkErrorCallback, + ChunkData? chunk, CancellationToken cancellationToken) + where TCommunication : class where TResponse : IMissingPayloadsCommunication, new() { if (chunk == null) @@ -140,9 +141,12 @@ protected async ValueTask ProcessChunk( catch (Exception ex) { Logger.LogDebug(ex, "Bad chunked communication for payload {payloadId}!", requestInfo.PayloadId); - return chunkErrorCallback("Chunked request completed with bad JSON!"); + completedCommunication = null; } + if (completedCommunication == null) + return chunkErrorCallback("Chunked request completed with bad JSON!"); + return await completionCallback(completedCommunication, cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 9fbd96cca9a..ad9bdf17288 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -16,6 +16,7 @@ using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Common.Extensions; using Tgstation.Server.Host.Components.Chat; +using Tgstation.Server.Host.Components.Chat.Commands; using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Interop; @@ -25,8 +26,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Session { /// @@ -61,7 +60,7 @@ public ApiValidationStatus ApiValidationStatus public RebootState RebootState => ReattachInformation.RebootState; /// - public Version DMApiVersion { get; private set; } + public Version? DMApiVersion { get; private set; } /// public bool TerminationWasRequested { get; private set; } @@ -123,7 +122,7 @@ async Task Wrap() /// /// The for the . /// - readonly IBridgeRegistration bridgeRegistration; + readonly IBridgeRegistration? bridgeRegistration; /// /// The for the . @@ -198,7 +197,7 @@ async Task Wrap() /// /// for shutting down the server if it is taking too long after validation. /// - volatile Task postValidationShutdownTask; + volatile Task? postValidationShutdownTask; /// /// The number of currently active calls to from TgsReboot(). @@ -374,7 +373,7 @@ await engineLock.StopServerProcess( } /// - public async ValueTask ProcessBridgeRequest(BridgeParameters parameters, CancellationToken cancellationToken) + public async ValueTask ProcessBridgeRequest(BridgeParameters parameters, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(parameters); @@ -406,7 +405,7 @@ public ValueTask Release() } /// - public ValueTask SendCommand(TopicParameters parameters, CancellationToken cancellationToken) + public ValueTask SendCommand(TopicParameters parameters, CancellationToken cancellationToken) => SendCommand(parameters, false, cancellationToken); /// @@ -453,7 +452,10 @@ public IAsyncDisposable ReplaceDmbProvider(IDmbProvider dmbProvider) /// public async ValueTask InstanceRenamed(string newInstanceName, CancellationToken cancellationToken) { - ReattachInformation.RuntimeInformation.InstanceName = newInstanceName; + var runtimeInformation = ReattachInformation.RuntimeInformation; + if (runtimeInformation != null) + runtimeInformation.InstanceName = newInstanceName; + await SendCommand( TopicParameters.CreateInstanceRenamedTopicParameters(newInstanceName), cancellationToken); @@ -519,7 +521,7 @@ async Task GetLaunchResult( var reattachResponse = await SendCommand( new TopicParameters( assemblyInformationProvider.Version, - ReattachInformation.RuntimeInformation.ServerPort), + ReattachInformation.RuntimeInformation!.ServerPort), true, reattachTopicCts.Token); @@ -533,7 +535,7 @@ async Task GetLaunchResult( ? LogLevel.Warning : LogLevel.Debug, "DMAPI Interop v{interopVersion} isn't returning the TGS custom commands list. Functionality added in v5.2.0.", - CompileJob.DMApiVersion.Semver()); + CompileJob.DMApiVersion!.Semver()); } } @@ -581,7 +583,7 @@ async Task PostValidationShutdown(Task proceedTask) /// The for the operation. /// A resulting in the for the request or if the request could not be dispatched. #pragma warning disable CA1502 // TODO: Decomplexify - async ValueTask ProcessBridgeCommand(BridgeParameters parameters, CancellationToken cancellationToken) + async ValueTask ProcessBridgeCommand(BridgeParameters parameters, CancellationToken cancellationToken) { var response = new BridgeResponse(); switch (parameters.CommandType) @@ -645,7 +647,7 @@ async ValueTask ProcessBridgeCommand(BridgeParameters parameters // TODO: When OD figures out how to unite port and topic_port, set an upper version bound on OD for this check if (DMApiVersion.Major != DMApiConstants.InteropVersion.Major - || (EngineVersion.Engine.Value == EngineType.OpenDream && DMApiVersion < new Version(5, 7))) + || (EngineVersion.Engine == EngineType.OpenDream && DMApiVersion < new Version(5, 7))) { apiValidationStatus = ApiValidationStatus.Incompatible; return BridgeError("Incompatible dmApiVersion!"); @@ -670,10 +672,11 @@ async ValueTask ProcessBridgeCommand(BridgeParameters parameters Logger.LogTrace("ApiValidationStatus set to {apiValidationStatus}", apiValidationStatus); + // we create new runtime info here because of potential .Dmb changes (i think. i forget...) response.RuntimeInformation = new RuntimeInformation( chatTrackingContext, ReattachInformation.Dmb, - ReattachInformation.RuntimeInformation.ServerVersion, + ReattachInformation.RuntimeInformation!.ServerVersion, ReattachInformation.RuntimeInformation.InstanceName, ReattachInformation.RuntimeInformation.SecurityLevel, ReattachInformation.RuntimeInformation.Visibility, @@ -688,7 +691,7 @@ async ValueTask ProcessBridgeCommand(BridgeParameters parameters } // Load custom commands - chatTrackingContext.CustomCommands = parameters.CustomCommands; + chatTrackingContext.CustomCommands = parameters.CustomCommands ?? Array.Empty(); chatTrackingContext.Active = true; Interlocked.Exchange(ref startupTcs, new TaskCompletionSource()).SetResult(); break; @@ -738,7 +741,7 @@ BridgeResponse BridgeError(string message) /// The to send. /// The for the operation. /// A resulting in the of the topic request. - async ValueTask SendTopicRequest(TopicParameters parameters, CancellationToken cancellationToken) + async ValueTask SendTopicRequest(TopicParameters parameters, CancellationToken cancellationToken) { parameters.AccessIdentifier = ReattachInformation.AccessIdentifier; @@ -764,14 +767,14 @@ async ValueTask SendTopicRequest(TopicParameters paramete var payloadId = NextPayloadId; // AccessIdentifer is just noise in a chunked request - parameters.AccessIdentifier = null; + parameters.AccessIdentifier = null!; GenerateQueryString(parameters, out json); // yes, this straight up ignores unicode, precalculating it is useless when we don't // even know if the UTF8 bytes of the url encoded chunk will fit the window until we do said encoding var fullPayloadSize = (uint)json.Length; - List chunkQueryStrings = null; + List? chunkQueryStrings = null; for (var chunkCount = 2; chunkQueryStrings == null; ++chunkCount) { var standardChunkSize = fullPayloadSize / chunkCount; @@ -817,7 +820,7 @@ async ValueTask SendTopicRequest(TopicParameters paramete Logger.LogTrace("Chunking topic request ({totalChunks} total)...", chunkQueryStrings.Count); - CombinedTopicResponse combinedResponse = null; + CombinedTopicResponse? combinedResponse = null; bool LogRequestIssue(bool possiblyFromCompletedRequest) { if (combinedResponse?.InteropResponse == null || combinedResponse.InteropResponse.ErrorMessage != null) @@ -841,11 +844,12 @@ bool LogRequestIssue(bool possiblyFromCompletedRequest) return null; } - while ((combinedResponse.InteropResponse.MissingChunks?.Count ?? 0) > 0) + while ((combinedResponse?.InteropResponse?.MissingChunks?.Count ?? 0) > 0) { Logger.LogWarning("DD is still missing some chunks of topic request P{payloadId}! Sending missing chunks...", payloadId); - var lastIndex = combinedResponse.InteropResponse.MissingChunks.Last(); - foreach (var missingChunkIndex in combinedResponse.InteropResponse.MissingChunks) + var missingChunks = combinedResponse!.InteropResponse!.MissingChunks!; + var lastIndex = missingChunks.Last(); + foreach (var missingChunkIndex in missingChunks) { var chunkCommandString = chunkQueryStrings[(int)missingChunkIndex]; combinedResponse = await SendRawTopic(chunkCommandString, topicPriority, cancellationToken); @@ -881,7 +885,7 @@ string GenerateQueryString(TopicParameters parameters, out string json) /// If this is a priority message. If so, the topic will make 5 attempts to send unless BYOND reboots or exits. /// The for the operation. /// A resulting in the of the topic request. - async ValueTask SendRawTopic(string queryString, bool priority, CancellationToken cancellationToken) + async ValueTask SendRawTopic(string queryString, bool priority, CancellationToken cancellationToken) { if (disposed) { @@ -891,7 +895,7 @@ async ValueTask SendRawTopic(string queryString, bool pri } var targetPort = ReattachInformation.TopicPort ?? ReattachInformation.Port; - Byond.TopicSender.TopicResponse byondResponse; + Byond.TopicSender.TopicResponse? byondResponse; using (await TopicSendSemaphore.Lock(cancellationToken)) byondResponse = await byondTopicSender.SendWithOptionalPriority( asyncDelayer, @@ -913,7 +917,7 @@ async ValueTask SendRawTopic(string queryString, bool pri var topicReturn = byondResponse.StringData; - TopicResponse interopResponse = null; + TopicResponse? interopResponse = null; if (topicReturn != null) try { @@ -934,7 +938,7 @@ async ValueTask SendRawTopic(string queryString, bool pri /// If waiting for the should be bypassed. /// The for the operation. /// A resulting in the of /world/Topic(). - async ValueTask SendCommand(TopicParameters parameters, bool bypassLaunchResult, CancellationToken cancellationToken) + async ValueTask SendCommand(TopicParameters parameters, bool bypassLaunchResult, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(parameters); @@ -996,7 +1000,7 @@ async ValueTask CancelIfLifetimeElapses() } } - TopicResponse fullResponse = null; + TopicResponse? fullResponse = null; var lifetimeWatchingTask = CancelIfLifetimeElapses(); try { @@ -1014,14 +1018,14 @@ void LogCombinedResponse() { Logger.LogTrace("Topic response is chunked..."); - ChunkData nextChunk = combinedResponse.InteropResponse.Chunk; + ChunkData? nextChunk = combinedResponse.InteropResponse.Chunk; do { var nextRequest = await ProcessChunk( (completedResponse, _) => { fullResponse = completedResponse; - return ValueTask.FromResult(null); + return ValueTask.FromResult(null); }, error => { From a47017d3189eef5918c71d85d7bcbafa143e9a14 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 22:06:23 -0500 Subject: [PATCH 701/717] Nullify `SessionControllerFactory` --- .../Session/ISessionControllerFactory.cs | 2 +- .../Session/SessionControllerFactory.cs | 42 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs index c6d1a634ff2..7058d3f4e49 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionControllerFactory.cs @@ -34,7 +34,7 @@ ValueTask LaunchNew( /// The to use. /// The for the operation. /// A resulting in a new on success or on failure to reattach. - ValueTask Reattach( + ValueTask Reattach( ReattachInformation reattachInformation, CancellationToken cancellationToken); } diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs index 79abda99a87..70bed0f5ba3 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs @@ -26,8 +26,6 @@ using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Session { /// @@ -227,7 +225,7 @@ public SessionControllerFactory( #pragma warning disable CA1506 // TODO: Decomplexify public async ValueTask LaunchNew( IDmbProvider dmbProvider, - IEngineExecutableLock currentByondLock, + IEngineExecutableLock? currentByondLock, DreamDaemonLaunchParameters launchParameters, bool apiValidate, CancellationToken cancellationToken) @@ -270,17 +268,17 @@ public async ValueTask LaunchNew( dmbProvider.CompileJob.Id); // mad this isn't abstracted but whatever - var engineType = dmbProvider.EngineVersion.Engine.Value; + var engineType = dmbProvider.EngineVersion.Engine!.Value; if (engineType == EngineType.Byond) await CheckPagerIsNotRunning(); await PortBindTest(launchParameters.Port.Value, engineType, cancellationToken); - string outputFilePath = null; + string? outputFilePath = null; var preserveLogFile = true; var hasStandardOutput = engineLock.HasStandardOutput; - if (launchParameters.LogOutput.Value) + if (launchParameters.LogOutput!.Value) { var now = DateTimeOffset.UtcNow; var dateDirectory = diagnosticsIOManager.ConcatPath(DreamDaemonLogsPath, now.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)); @@ -322,8 +320,8 @@ public async ValueTask LaunchNew( var runtimeInformation = CreateRuntimeInformation( dmbProvider, chatTrackingContext, - launchParameters.SecurityLevel.Value, - launchParameters.Visibility.Value, + launchParameters.SecurityLevel!.Value, + launchParameters.Visibility!.Value, apiValidate); var reattachInformation = new ReattachInformation( @@ -335,7 +333,7 @@ public async ValueTask LaunchNew( var byondTopicSender = topicClientFactory.CreateTopicClient( TimeSpan.FromMilliseconds( - launchParameters.TopicRequestTimeout.Value)); + launchParameters.TopicRequestTimeout!.Value)); var sessionController = new SessionController( reattachInformation, @@ -387,7 +385,7 @@ public async ValueTask LaunchNew( #pragma warning restore CA1506 /// - public async ValueTask Reattach( + public async ValueTask Reattach( ReattachInformation reattachInformation, CancellationToken cancellationToken) { @@ -452,19 +450,21 @@ public async ValueTask Reattach( } catch { - chatTrackingContext.Dispose(); + chatTrackingContext?.Dispose(); throw; } } catch { - await process.DisposeAsync(); + if (process != null) + await process.DisposeAsync(); + throw; } } catch { - engineLock.Dispose(); + engineLock?.Dispose(); throw; } } @@ -476,7 +476,7 @@ public async ValueTask Reattach( /// The . /// The . /// The secure string to use for the session. - /// The full path to log DreamDaemon output to. + /// The optional full path to log DreamDaemon output to. /// If we are only validating the DMAPI then exiting. /// The for the operation. /// A resulting in the DreamDaemon . @@ -485,7 +485,7 @@ async ValueTask CreateGameServerProcess( IEngineExecutableLock engineLock, DreamDaemonLaunchParameters launchParameters, string accessIdentifier, - string logFilePath, + string? logFilePath, bool apiValidate, CancellationToken cancellationToken) { @@ -557,19 +557,19 @@ await eventConsumer.HandleEvent( /// If , will be deleted. /// The for the operation. /// A representing the running operation. - async ValueTask LogDDOutput(IProcess process, string outputFilePath, bool cliSupported, bool preserveFile, CancellationToken cancellationToken) + async ValueTask LogDDOutput(IProcess process, string? outputFilePath, bool cliSupported, bool preserveFile, CancellationToken cancellationToken) { try { - string ddOutput = null; + string? ddOutput = null; if (cliSupported) - ddOutput = await process.GetCombinedOutput(cancellationToken); + ddOutput = (await process.GetCombinedOutput(cancellationToken))!; if (ddOutput == null) try { var dreamDaemonLogBytes = await gameIOManager.ReadAllBytes( - outputFilePath, + outputFilePath!, cancellationToken); ddOutput = Encoding.UTF8.GetString(dreamDaemonLogBytes); @@ -580,7 +580,7 @@ async ValueTask LogDDOutput(IProcess process, string outputFilePath, bool cliSup try { logger.LogTrace("Deleting temporary log file {path}...", outputFilePath); - await gameIOManager.DeleteFile(outputFilePath, cancellationToken); + await gameIOManager.DeleteFile(outputFilePath!, cancellationToken); } catch (Exception ex) { @@ -620,7 +620,7 @@ RuntimeInformation CreateRuntimeInformation( chatTrackingContext, dmbProvider, assemblyInformationProvider.Version, - instance.Name, + instance.Name!, securityLevel, visibility, serverPortProvider.HttpApiPort, From 071de7b466e18d2d10e611e90b27c50fa3afc286 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 22:08:30 -0500 Subject: [PATCH 702/717] Nullify `SessionPersistor` --- .../Components/Session/SessionPersistor.cs | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs index 2cd093c3eea..a916ea792ba 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs @@ -8,12 +8,11 @@ using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Database; +using Tgstation.Server.Host.Models; using Tgstation.Server.Host.System; using Z.EntityFramework.Plus; -#nullable disable - namespace Tgstation.Server.Host.Components.Session { /// @@ -77,8 +76,8 @@ public ValueTask Save(ReattachInformation reattachInformation, CancellationToken var dbReattachInfo = new Models.ReattachInformation(reattachInformation.AccessIdentifier) { - CompileJobId = reattachInformation.Dmb.CompileJob.Id.Value, - InitialCompileJobId = reattachInformation.InitialDmb?.CompileJob.Id.Value, + CompileJobId = reattachInformation.Dmb.CompileJob.Require(x => x.Id), + InitialCompileJobId = reattachInformation.InitialDmb?.CompileJob.Require(x => x.Id), Port = reattachInformation.Port, ProcessId = reattachInformation.ProcessId, RebootState = reattachInformation.RebootState, @@ -89,7 +88,7 @@ public ValueTask Save(ReattachInformation reattachInformation, CancellationToken db.ReattachInformations.Add(dbReattachInfo); await db.Save(cancellationToken); - reattachInformation.Id = dbReattachInfo.Id.Value; + reattachInformation.Id = dbReattachInfo.Id!.Value; logger.LogDebug("Saved reattach information: {info}", reattachInformation); }); @@ -110,8 +109,8 @@ public ValueTask Update(ReattachInformation reattachInformation, CancellationTok db.ReattachInformations.Attach(dbReattachInfo); dbReattachInfo.AccessIdentifier = reattachInformation.AccessIdentifier; - dbReattachInfo.CompileJobId = reattachInformation.Dmb.CompileJob.Id.Value; - dbReattachInfo.InitialCompileJobId = reattachInformation.InitialDmb?.CompileJob.Id.Value; + dbReattachInfo.CompileJobId = reattachInformation.Dmb.CompileJob.Require(x => x.Id); + dbReattachInfo.InitialCompileJobId = reattachInformation.InitialDmb?.CompileJob.Require(x => x.Id); dbReattachInfo.Port = reattachInformation.Port; dbReattachInfo.ProcessId = reattachInformation.ProcessId; dbReattachInfo.RebootState = reattachInformation.RebootState; @@ -124,9 +123,9 @@ public ValueTask Update(ReattachInformation reattachInformation, CancellationTok }); /// - public async ValueTask Load(CancellationToken cancellationToken) + public async ValueTask Load(CancellationToken cancellationToken) { - Models.ReattachInformation result = null; + Models.ReattachInformation? result = null; TimeSpan? topicTimeout = null; async ValueTask KillProcess(Models.ReattachInformation reattachInfo) @@ -160,19 +159,19 @@ await databaseContextFactory.UseContext(async (db) => var dbReattachInfos = await db .ReattachInformations .AsQueryable() - .Where(x => x.CompileJob.Job.Instance.Id == metadata.Id) + .Where(x => x.CompileJob!.Job.Instance!.Id == metadata.Id) .Include(x => x.CompileJob) .Include(x => x.InitialCompileJob) .ToListAsync(cancellationToken); result = dbReattachInfos.FirstOrDefault(); - if (result == default) + if (result == null) return; var timeoutMilliseconds = await db .Instances .AsQueryable() .Where(x => x.Id == metadata.Id) - .Select(x => x.DreamDaemonSettings.TopicRequestTimeout) + .Select(x => x.DreamDaemonSettings!.TopicRequestTimeout) .FirstOrDefaultAsync(cancellationToken); if (timeoutMilliseconds == default) @@ -207,7 +206,7 @@ await databaseContextFactory.UseContext(async (db) => return null; } - var dmb = await dmbFactory.FromCompileJob(result.CompileJob, cancellationToken); + var dmb = await dmbFactory.FromCompileJob(result!.CompileJob!, cancellationToken); if (dmb == null) { logger.LogError("Unable to reattach! Could not load .dmb!"); @@ -225,7 +224,7 @@ await db return null; } - IDmbProvider initialDmb = null; + IDmbProvider? initialDmb = null; if (result.InitialCompileJob != null) { logger.LogTrace("Loading initial compile job..."); @@ -266,7 +265,7 @@ async ValueTask ClearImpl(IDatabaseContext databaseContext, bool instant, Cancel var baseQuery = databaseContext .ReattachInformations .AsQueryable() - .Where(x => x.CompileJob.Job.Instance.Id == metadata.Id); + .Where(x => x.CompileJob!.Job.Instance!.Id == metadata.Id); if (instant) await baseQuery From 3c62327d1d87d9684dbb1d7f2cfb8912530f9f9a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 22:08:56 -0500 Subject: [PATCH 703/717] Nullify `TopicClientFactory` --- .../Components/Session/TopicClientFactory.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs b/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs index dc51016b29b..3ed153a6412 100644 --- a/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs +++ b/src/Tgstation.Server.Host/Components/Session/TopicClientFactory.cs @@ -4,8 +4,6 @@ using Microsoft.Extensions.Logging; -#nullable disable - namespace Tgstation.Server.Host.Components.Session { /// @@ -14,7 +12,7 @@ sealed class TopicClientFactory : ITopicClientFactory /// /// The for created s. /// - readonly ILogger logger; + readonly ILogger? logger; /// /// Initializes a new instance of the class. From c40720df8093173d65b7671ad5110bf2cfdd77ca Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 22:24:36 -0500 Subject: [PATCH 704/717] Cleanup a `JobsHubTests` assert --- tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs index 84985b6a9bf..b3149556e56 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/JobsHubTests.cs @@ -44,7 +44,7 @@ public JobsHubTests(IServerClient permedUser, IServerClient permlessUser) finishTcs = new TaskCompletionSource(); seenJobs = new ConcurrentDictionary(); - permlessSeenJobs = new HashSet(); + permlessSeenJobs = []; } public Task ReceiveJobUpdate(JobResponse job, CancellationToken cancellationToken) @@ -199,7 +199,7 @@ await permedUser.Instances.Update(new InstanceUpdateRequest } static DateTimeOffset PerformDBTruncation(DateTimeOffset original) - => new DateTimeOffset( + => new( original.Ticks - (original.Ticks % TimeSpan.TicksPerSecond), original.Offset); @@ -234,7 +234,7 @@ static DateTimeOffset PerformDBTruncation(DateTimeOffset original) Assert.IsTrue(accountedJobs <= seenJobs.Count); Assert.AreNotEqual(0, permlessSeenJobs.Count); Assert.IsTrue(permlessSeenJobs.Count < seenJobs.Count); - Assert.IsTrue(permlessSeenJobs.All(id => seenJobs.ContainsKey(id))); + Assert.IsTrue(permlessSeenJobs.All(id => seenJobs.ContainsKey(id)), $"Saw permless job(s) that wasn't seen:{Environment.NewLine}{JobListFormatter(permlessSeenJobs.Where(id => !seenJobs.ContainsKey(id)).Select(id => allJobs.First(x => x.Id == id)))}"); await using var conn3 = (HubConnection)await permedUser.SubscribeToJobUpdates( this, From 9a3c0aaf82db43baf6a5076194658b9045c2ba31 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 23:36:02 -0500 Subject: [PATCH 705/717] Nullify `AdvancedWatchdog` --- .../Components/Watchdog/AdvancedWatchdog.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs index 0b08ed062b1..3698367f1f6 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs @@ -18,8 +18,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Watchdog { /// @@ -30,7 +28,7 @@ abstract class AdvancedWatchdog : BasicWatchdog /// /// The for . /// - protected SwappableDmbProvider ActiveSwappable { get; private set; } + protected SwappableDmbProvider? ActiveSwappable { get; private set; } /// /// The for the . @@ -45,12 +43,12 @@ abstract class AdvancedWatchdog : BasicWatchdog /// /// The active for . /// - SwappableDmbProvider pendingSwappable; + SwappableDmbProvider? pendingSwappable; /// /// The representing the cleanup of an unused . /// - volatile TaskCompletionSource deploymentCleanupGate; + volatile TaskCompletionSource? deploymentCleanupGate; /// /// Initializes a new instance of the class. @@ -178,7 +176,7 @@ protected sealed override async ValueTask HandleNormalReboot(Canc var localDeploymentCleanupGate = new TaskCompletionSource(); async Task CleanupLingeringDeployment() { - var lingeringDeploymentExpirySeconds = ActiveLaunchParameters.StartupTimeout.Value; + var lingeringDeploymentExpirySeconds = ActiveLaunchParameters.StartupTimeout!.Value; Logger.LogDebug( "Holding old deployment {compileJobId} for up to {expiry} seconds...", currentCompileJobId, @@ -262,7 +260,7 @@ protected sealed override async ValueTask HandleNewDmbAvailable(CancellationToke return; } - SwappableDmbProvider swappableProvider = null; + SwappableDmbProvider? swappableProvider = null; try { swappableProvider = CreateSwappableDmbProvider(compileJobProvider); @@ -350,9 +348,9 @@ protected override async ValueTask HandleMonitorWakeup(MonitorAct /// if swapping is possible, otherwise. bool CanUseSwappableDmbProvider(IDmbProvider dmbProvider) { - if (dmbProvider.EngineVersion.Engine.Value != EngineType.Byond) + if (dmbProvider.EngineVersion.Engine != EngineType.Byond) { - Logger.LogDebug("Not using SwappableDmbProvider for engine type {engineType}", dmbProvider.EngineVersion.Engine.Value); + Logger.LogDebug("Not using SwappableDmbProvider for engine type {engineType}", dmbProvider.EngineVersion.Engine); return false; } @@ -366,7 +364,7 @@ bool CanUseSwappableDmbProvider(IDmbProvider dmbProvider) /// A representing the running operation. async ValueTask InitialLink(CancellationToken cancellationToken) { - await ActiveSwappable.FinishActivationPreparation(cancellationToken); + await ActiveSwappable!.FinishActivationPreparation(cancellationToken); Logger.LogTrace("Linking compile job..."); await ActiveSwappable.MakeActive(cancellationToken); } From b1878d697a4d87065f139a60a7099208d0bbf93e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 23:37:14 -0500 Subject: [PATCH 706/717] Nullify `IWatchdog` --- src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs index 8699c17c6cc..96c6c9ccf9a 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdog.cs @@ -7,8 +7,6 @@ using Tgstation.Server.Host.Components.Events; using Tgstation.Server.Host.Components.Session; -#nullable disable - namespace Tgstation.Server.Host.Components.Watchdog { /// @@ -34,7 +32,7 @@ public interface IWatchdog : IComponentService, IAsyncDisposable, IEventConsumer /// /// Retrieves the currently running on the server. /// - Models.CompileJob ActiveCompileJob { get; } + Models.CompileJob? ActiveCompileJob { get; } /// /// The to be applied. @@ -45,7 +43,7 @@ public interface IWatchdog : IComponentService, IAsyncDisposable, IEventConsumer /// The the active server is using. /// /// This may not be the exact same as but still be associated with the same session. - DreamDaemonLaunchParameters LastLaunchParameters { get; } + DreamDaemonLaunchParameters? LastLaunchParameters { get; } /// /// The of the active server. From c37d3ef7cbb78b4af997a24e23df5811415fc7cf Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 23:38:14 -0500 Subject: [PATCH 707/717] Nullify `IWatchdogFactory` --- src/Tgstation.Server.Host/Components/InstanceFactory.cs | 2 +- .../Components/Watchdog/IWatchdogFactory.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index 7f621333e83..2b24bcb6cb4 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -324,7 +324,7 @@ public async ValueTask CreateInstance(IBridgeRegistrar bridgeRegistra configuration, // watchdog doesn't need itself as an event consumer remoteDeploymentManagerFactory, metadata, - metadata.DreamDaemonSettings); + metadata.DreamDaemonSettings!); try { eventConsumer.SetWatchdog(watchdog); diff --git a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs index eff60cf7111..308cd3db54c 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/IWatchdogFactory.cs @@ -6,8 +6,6 @@ using Tgstation.Server.Host.Components.Session; using Tgstation.Server.Host.IO; -#nullable disable - namespace Tgstation.Server.Host.Components.Watchdog { /// From 1f8d24835b5a5b54e891d1108336bfe2dbe9eb8e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 23:38:53 -0500 Subject: [PATCH 708/717] Nullify `PosixWatchdog` --- src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs index 7b142d6b546..27874178afa 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs @@ -17,8 +17,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Watchdog { /// From 2b0eefca238bc30fbfb710d762abbabb3d2ae0b6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 23:39:13 -0500 Subject: [PATCH 709/717] Nullify `PosixWatchdogFactory` --- .../Components/Watchdog/PosixWatchdogFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdogFactory.cs index 491f0ff3625..1d0d140bc05 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdogFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdogFactory.cs @@ -16,8 +16,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Watchdog { /// From 418b627b44970f633bba00a5d7c531fd04206021 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 23:39:29 -0500 Subject: [PATCH 710/717] Nullify `WatchdogFactory` --- .../Components/Watchdog/WatchdogFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs index 868155d3dcf..e9a37ecb2b5 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogFactory.cs @@ -15,8 +15,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Watchdog { /// From 26a1e618761da2af60cc346404293ff9503dba5f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 23:39:51 -0500 Subject: [PATCH 711/717] Nullify `WindowsWatchdogFactory` --- .../Components/Watchdog/WindowsWatchdogFactory.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs index cd78148c373..89ed6b145d7 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdogFactory.cs @@ -15,8 +15,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Watchdog { /// From a7caf35a6b0e7e6ce1e19ef73d8d77c2f8ca0b9b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 23:40:15 -0500 Subject: [PATCH 712/717] Nullify `WindowsWatchdog` --- .../Components/Watchdog/WindowsWatchdog.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs index 98a8d0da466..4fb87385c97 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs @@ -15,8 +15,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Watchdog { /// @@ -83,9 +81,9 @@ public WindowsWatchdog( /// protected override async ValueTask ApplyInitialDmb(CancellationToken cancellationToken) { - if (Server.EngineVersion.Engine.Value != EngineType.Byond) + if (Server.EngineVersion.Engine != EngineType.Byond) { - Logger.LogTrace("Not setting InitialDmb for engine type {engineType}", Server.EngineVersion.Engine.Value); + Logger.LogTrace("Not setting InitialDmb for engine type {engineType}", Server.EngineVersion.Engine); return; } From 9db05f82ec577d2031421a7c1f5615b7387ece2c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 23:45:14 -0500 Subject: [PATCH 713/717] Nullify `BasicWatchdog` --- .../Components/Watchdog/AdvancedWatchdog.cs | 11 ++++--- .../Components/Watchdog/BasicWatchdog.cs | 33 ++++++++----------- .../Components/Watchdog/WindowsWatchdog.cs | 2 +- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs index 3698367f1f6..347048921df 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs @@ -141,11 +141,12 @@ protected sealed override async ValueTask HandleNormalReboot(Canc ValueTask RunPrequel() => BeforeApplyDmb(pendingSwappable.CompileJob, cancellationToken); var needToSwap = !pendingSwappable.Swapped; + var controller = Server!; if (needToSwap) { // IMPORTANT: THE SESSIONCONTROLLER SHOULD STILL BE PROCESSING THE BRIDGE REQUEST SO WE KNOW DD IS SLEEPING // OTHERWISE, IT COULD RETURN TO /world/Reboot() TOO EARLY AND LOAD THE WRONG .DMB - if (!Server.ProcessingRebootBridgeRequest) + if (!controller.ProcessingRebootBridgeRequest) { // integration test logging will catch this Logger.LogError( @@ -168,7 +169,7 @@ protected sealed override async ValueTask HandleNormalReboot(Canc if (needToSwap) await PerformDmbSwap(pendingSwappable, cancellationToken); - var currentCompileJobId = Server.ReattachInformation.Dmb.CompileJob.Id; + var currentCompileJobId = controller.ReattachInformation.Dmb.CompileJob.Id; await DrainDeploymentCleanupTasks(false); @@ -209,7 +210,7 @@ async Task CleanupLingeringDeployment() lock (deploymentCleanupTasks) { - lingeringDeployment = Server.ReplaceDmbProvider(pendingSwappable); + lingeringDeployment = controller.ReplaceDmbProvider(pendingSwappable); deploymentCleanupTasks.Add( CleanupLingeringDeployment()); } @@ -217,7 +218,7 @@ async Task CleanupLingeringDeployment() ActiveSwappable = pendingSwappable; pendingSwappable = null; - await SessionPersistor.Update(Server.ReattachInformation, cancellationToken); + await SessionPersistor.Update(controller.ReattachInformation, cancellationToken); await updateTask; } else @@ -382,7 +383,7 @@ async ValueTask PerformDmbSwap(SwappableDmbProvider newProvider, CancellationTok await newProvider.FinishActivationPreparation(cancellationToken); var suspended = false; - var server = Server; + var server = Server!; try { server.SuspendProcess(); diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index d9f37a6f555..37b9bed41c6 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -17,8 +17,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Watchdog { /// @@ -35,7 +33,7 @@ class BasicWatchdog : WatchdogBase /// /// The single . /// - protected ISessionController Server { get; private set; } + protected ISessionController? Server { get; private set; } /// /// If the server is set to gracefully reboot due to a pending dmb or settings change. @@ -111,16 +109,17 @@ public sealed override ValueTask InstanceRenamed(string newInstanceName, Cancell /// protected override async ValueTask HandleMonitorWakeup(MonitorActivationReason reason, CancellationToken cancellationToken) { + var controller = Server!; switch (reason) { case MonitorActivationReason.ActiveServerCrashed: - var eventType = Server.TerminationWasRequested + var eventType = controller.TerminationWasRequested ? EventType.WorldEndProcess : EventType.WatchdogCrash; await HandleEventImpl(eventType, Enumerable.Empty(), false, cancellationToken); - var exitWord = Server.TerminationWasRequested ? "exited" : "crashed"; - if (Server.RebootState == Session.RebootState.Shutdown) + var exitWord = controller.TerminationWasRequested ? "exited" : "crashed"; + if (controller.RebootState == Session.RebootState.Shutdown) { // the time for graceful shutdown is now Chat.QueueWatchdogMessage( @@ -138,7 +137,7 @@ protected override async ValueTask HandleMonitorWakeup(MonitorAct exitWord)); return MonitorAction.Restart; case MonitorActivationReason.ActiveServerRebooted: - var rebootState = Server.RebootState; + var rebootState = controller.RebootState; if (gracefulRebootRequired && rebootState == Session.RebootState.Normal) { Logger.LogError("Watchdog reached normal reboot state with gracefulRebootRequired set!"); @@ -146,7 +145,7 @@ protected override async ValueTask HandleMonitorWakeup(MonitorAct } gracefulRebootRequired = false; - Server.ResetRebootState(); + controller.ResetRebootState(); var eventTask = HandleEventImpl(EventType.WorldReboot, Enumerable.Empty(), false, cancellationToken); try @@ -172,7 +171,7 @@ protected override async ValueTask HandleMonitorWakeup(MonitorAct } case MonitorActivationReason.ActiveLaunchParametersUpdated: - await Server.SetRebootState(Session.RebootState.Restart, cancellationToken); + await controller.SetRebootState(Session.RebootState.Restart, cancellationToken); gracefulRebootRequired = true; break; case MonitorActivationReason.NewDmbAvailable: @@ -204,7 +203,7 @@ protected override async ValueTask DisposeAndNullControllersImpl() } /// - protected sealed override ISessionController GetActiveController() => Server; + protected sealed override ISessionController? GetActiveController() => Server; /// protected override async ValueTask InitController( @@ -222,15 +221,14 @@ protected override async ValueTask InitController( // start the alpha server task, either by launch a new process or attaching to an existing one // The tasks returned are mainly for writing interop files to the directories among other things and should generally never fail // The tasks pertaining to server startup times are in the ISessionControllers - ValueTask serverLaunchTask; if (!reattachInProgress) { - Logger.LogTrace("Initializing controller with CompileJob {compileJobId}...", dmbToUse.CompileJob.Id); + Logger.LogTrace("Initializing controller with CompileJob {compileJobId}...", dmbToUse!.CompileJob.Id); await BeforeApplyDmb(dmbToUse.CompileJob, cancellationToken); dmbToUse = await PrepServerForLaunch(dmbToUse, cancellationToken); await eventTask; - serverLaunchTask = SessionControllerFactory.LaunchNew( + Server = await SessionControllerFactory.LaunchNew( dmbToUse, null, ActiveLaunchParameters, @@ -240,12 +238,9 @@ protected override async ValueTask InitController( else { await eventTask; - serverLaunchTask = SessionControllerFactory.Reattach(reattachInfo, cancellationToken); + Server = await SessionControllerFactory.Reattach(reattachInfo!, cancellationToken); } - // retrieve the session controller - Server = await serverLaunchTask; - // possiblity of null servers due to failed reattaches if (Server == null) { @@ -293,7 +288,7 @@ await ReattachFailure( /// The for the operation. /// A representing the running operation. protected virtual ValueTask SessionStartupPersist(CancellationToken cancellationToken) - => SessionPersistor.Save(Server.ReattachInformation, cancellationToken); + => SessionPersistor.Save(Server!.ReattachInformation, cancellationToken); /// /// Handler for when the is . @@ -311,7 +306,7 @@ protected virtual ValueTask HandleNormalReboot(CancellationToken protected virtual async ValueTask HandleNewDmbAvailable(CancellationToken cancellationToken) { gracefulRebootRequired = true; - if (Server.CompileJob.DMApiVersion == null) + if (Server!.CompileJob.DMApiVersion == null) { Chat.QueueWatchdogMessage( "A new deployment has been made but cannot be applied automatically as the currently running server has no DMAPI. Please manually reboot the server to apply the update."); diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs index 4fb87385c97..e75ba745119 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WindowsWatchdog.cs @@ -81,7 +81,7 @@ public WindowsWatchdog( /// protected override async ValueTask ApplyInitialDmb(CancellationToken cancellationToken) { - if (Server.EngineVersion.Engine != EngineType.Byond) + if (Server!.EngineVersion.Engine != EngineType.Byond) { Logger.LogTrace("Not setting InitialDmb for engine type {engineType}", Server.EngineVersion.Engine); return; From 7b458a67da0016e8075ec1d646c9eae58ce2a297 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 23 Dec 2023 23:55:25 -0500 Subject: [PATCH 714/717] Nullify `WatchdogBase` --- .../Components/Watchdog/AdvancedWatchdog.cs | 4 +- .../Components/Watchdog/BasicWatchdog.cs | 2 +- .../Components/Watchdog/WatchdogBase.cs | 137 +++++++++++------- 3 files changed, 87 insertions(+), 56 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs index 347048921df..884541e9fb8 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/AdvancedWatchdog.cs @@ -233,7 +233,7 @@ protected sealed override async ValueTask HandleNewDmbAvailable(CancellationToke IDmbProvider compileJobProvider = DmbFactory.LockNextDmb(1); bool canSeamlesslySwap = CanUseSwappableDmbProvider(compileJobProvider); if (canSeamlesslySwap) - if (compileJobProvider.CompileJob.EngineVersion != ActiveCompileJob.EngineVersion) + if (compileJobProvider.CompileJob.EngineVersion != ActiveCompileJob!.EngineVersion) { // have to do a graceful restart Logger.LogDebug( @@ -265,7 +265,7 @@ protected sealed override async ValueTask HandleNewDmbAvailable(CancellationToke try { swappableProvider = CreateSwappableDmbProvider(compileJobProvider); - if (ActiveCompileJob.DMApiVersion == null) + if (ActiveCompileJob!.DMApiVersion == null) { Logger.LogWarning("Active compile job has no DMAPI! Commencing immediate .dmb swap. Note this behavior is known to be buggy in some DM code contexts. See https://github.com/tgstation/tgstation-server/issues/1550"); await PerformDmbSwap(swappableProvider, cancellationToken); diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index 37b9bed41c6..10b6a7b19ca 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -208,7 +208,7 @@ protected override async ValueTask DisposeAndNullControllersImpl() /// protected override async ValueTask InitController( ValueTask eventTask, - ReattachInformation reattachInfo, + ReattachInformation? reattachInfo, CancellationToken cancellationToken) { // don't need a new dmb if reattaching diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs index 0750f006d60..e9223229956 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs @@ -27,8 +27,6 @@ using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Utils; -#nullable disable - namespace Tgstation.Server.Host.Components.Watchdog { /// @@ -58,10 +56,10 @@ public WatchdogStatus Status public DreamDaemonLaunchParameters ActiveLaunchParameters { get; protected set; } /// - public DreamDaemonLaunchParameters LastLaunchParameters { get; protected set; } + public DreamDaemonLaunchParameters? LastLaunchParameters { get; protected set; } /// - public Models.CompileJob ActiveCompileJob => GetActiveController()?.CompileJob; + public Models.CompileJob? ActiveCompileJob => GetActiveController()?.CompileJob; /// public abstract RebootState? RebootState { get; } @@ -154,12 +152,12 @@ public WatchdogStatus Status /// /// The for the monitor loop. /// - CancellationTokenSource monitorCts; + CancellationTokenSource? monitorCts; /// /// The running the monitor loop. /// - Task monitorTask; + Task? monitorTask; /// /// Backing field for . @@ -395,7 +393,7 @@ await jobManager.RegisterOperation( job, async (core, databaseContextFactory, paramJob, progressFunction, ct) => { - if (core.Watchdog != this) + if (core?.Watchdog != this) throw new InvalidOperationException(Instance.DifferentCoreExceptionMessage); using (await SemaphoreSlimContext.Lock(synchronizationSemaphore, ct)) @@ -418,7 +416,7 @@ public async ValueTask Terminate(bool graceful, CancellationToken cancellationTo } /// - public async ValueTask HandleRestart(Version updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken) + public async ValueTask HandleRestart(Version? updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken) { if (handlerMayDelayShutdownWithExtremelyLongRunningTasks) { @@ -427,7 +425,7 @@ public async ValueTask HandleRestart(Version updateVersion, bool handlerMayDelay if (Status != WatchdogStatus.Offline) { Logger.LogDebug("Waiting for server to gracefully shut down."); - await monitorTask.WaitAsync(cancellationToken); + await monitorTask!.WaitAsync(cancellationToken); } else Logger.LogTrace("Graceful shutdown requested but server is already offline."); @@ -490,7 +488,7 @@ public async ValueTask Broadcast(string message, CancellationToken cancell } /// - async ValueTask IEventConsumer.HandleEvent(EventType eventType, IEnumerable parameters, bool deploymentPipeline, CancellationToken cancellationToken) + async ValueTask IEventConsumer.HandleEvent(EventType eventType, IEnumerable parameters, bool deploymentPipeline, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(parameters); @@ -516,7 +514,7 @@ async ValueTask IEventConsumer.HandleEvent(EventType eventType, IEnumerable to use, if any. /// The for the operation. /// A representing the running operation. - protected abstract ValueTask InitController(ValueTask eventTask, ReattachInformation reattachInfo, CancellationToken cancellationToken); + protected abstract ValueTask InitController(ValueTask eventTask, ReattachInformation? reattachInfo, CancellationToken cancellationToken); /// /// Launches the watchdog. @@ -531,7 +529,7 @@ protected async ValueTask LaunchNoLock( bool startMonitor, bool announce, bool announceFailure, - ReattachInformation reattachInfo, + ReattachInformation? reattachInfo, CancellationToken cancellationToken) { Logger.LogTrace("Begin LaunchImplNoLock"); @@ -612,7 +610,7 @@ protected async ValueTask StopMonitor() if (monitorTask == null) return false; var wasRunning = !monitorTask.IsCompleted; - monitorCts.Cancel(); + monitorCts!.Cancel(); await monitorTask; Logger.LogTrace("Stopped Monitor"); monitorCts.Dispose(); @@ -640,7 +638,7 @@ protected async ValueTask CheckLaunchResult(ISessionController controller, strin if (!launchResult.StartupTime.HasValue) throw new JobException( ErrorCode.WatchdogStartupTimeout, - new JobException($"{serverName} timed out on startup: {ActiveLaunchParameters.StartupTimeout.Value}s")); + new JobException($"{serverName} timed out on startup: {ActiveLaunchParameters.StartupTimeout!.Value}s")); } /// @@ -685,8 +683,8 @@ protected async ValueTask DisposeAndNullControllers(CancellationToken cancellati /// /// Get the active . /// - /// The active . - protected abstract ISessionController GetActiveController(); + /// The active , if any. + protected abstract ISessionController? GetActiveController(); /// /// Handles the actions to take when the monitor has to "wake up". @@ -718,9 +716,9 @@ protected async ValueTask BeforeApplyDmb(Models.CompileJob newCompileJob, Cancel var eventTask = eventConsumer.HandleEvent( EventType.DeploymentActivation, - new List + new List { - GameIOManager.ResolvePath(newCompileJob.DirectoryName.ToString()), + GameIOManager.ResolvePath(newCompileJob.DirectoryName!.Value.ToString()), }, false, cancellationToken); @@ -845,13 +843,14 @@ async Task MonitorLifetimes(CancellationToken cancellationToken) try { MonitorAction nextAction = MonitorAction.Continue; - Task activeServerLifetime = null, + Task? activeServerLifetime = null, activeServerReboot = null, activeServerStartup = null, serverPrimed = null, activeLaunchParametersChanged = null, - newDmbAvailable = null; - ISessionController lastController = null; + newDmbAvailable = null, + healthCheck = null; + ISessionController? lastController = null; var ranInitialDmbCheck = false; for (ulong iteration = 1; nextAction != MonitorAction.Exit; ++iteration) using (LogContext.PushProperty(SerilogContextHelper.WatchdogMonitorIterationContextProperty, iteration)) @@ -867,7 +866,7 @@ async Task MonitorLifetimes(CancellationToken cancellationToken) void UpdateMonitoredTasks() { var sameController = lastController == controller; - void TryUpdateTask(ref Task oldTask, Func newTaskFactory) + void TryUpdateTask(ref Task? oldTask, Func newTaskFactory) { if (sameController && oldTask?.IsCompleted == true) return; @@ -875,7 +874,7 @@ void TryUpdateTask(ref Task oldTask, Func newTaskFactory) oldTask = newTaskFactory(); } - controller.RebootGate = nextMonitorWakeupTcs.Task; + controller!.RebootGate = nextMonitorWakeupTcs.Task; TryUpdateTask(ref activeServerLifetime, () => controller.Lifetime); TryUpdateTask(ref activeServerReboot, () => controller.OnReboot); @@ -898,28 +897,36 @@ void TryUpdateTask(ref Task oldTask, Func newTaskFactory) }); } - UpdateMonitoredTasks(); - - var healthCheckSeconds = ActiveLaunchParameters.HealthCheckSeconds.Value; - var healthCheck = healthCheckSeconds == 0 - || !controller.DMApiAvailable - ? Extensions.TaskExtensions.InfiniteTask - : Task.Delay( - TimeSpan.FromSeconds(healthCheckSeconds), - cancellationToken); - - // cancel waiting if requested - var toWaitOn = Task.WhenAny( - activeServerLifetime, - activeServerReboot, - activeServerStartup, - healthCheck, - newDmbAvailable, - activeLaunchParametersChanged, - serverPrimed); - - // wait for something to happen - await toWaitOn.WaitAsync(cancellationToken); + if (controller != null) + { + UpdateMonitoredTasks(); + + var healthCheckSeconds = ActiveLaunchParameters.HealthCheckSeconds!.Value; + healthCheck = healthCheckSeconds == 0 + || !controller.DMApiAvailable + ? Extensions.TaskExtensions.InfiniteTask + : Task.Delay( + TimeSpan.FromSeconds(healthCheckSeconds), + cancellationToken); + + // cancel waiting if requested + var toWaitOn = Task.WhenAny( + activeServerLifetime!, + activeServerReboot!, + activeServerStartup!, + healthCheck, + newDmbAvailable!, + activeLaunchParametersChanged!, + serverPrimed!); + + // wait for something to happen + await toWaitOn.WaitAsync(cancellationToken); + } + else + { + Logger.LogError("Controller was null on monitor wakeup! Attempting restart..."); + nextAction = MonitorAction.Restart; // excuse me wtf? + } cancellationToken.ThrowIfCancellationRequested(); Logger.LogTrace("Monitor activated"); @@ -928,7 +935,7 @@ void TryUpdateTask(ref Task oldTask, Func newTaskFactory) using (await SemaphoreSlimContext.Lock(synchronizationSemaphore, cancellationToken)) { // Set this sooner so chat sends don't hold us up - if (activeServerLifetime.IsCompleted) + if (activeServerLifetime!.IsCompleted) Status = WatchdogStatus.Restoring; // multiple things may have happened, handle them one at a time @@ -936,7 +943,7 @@ void TryUpdateTask(ref Task oldTask, Func newTaskFactory) { MonitorActivationReason activationReason = default; // this will always be assigned before being used - bool CheckActivationReason(ref Task task, MonitorActivationReason testActivationReason) + bool CheckActivationReason(ref Task? task, MonitorActivationReason testActivationReason) { var taskCompleted = task?.IsCompleted == true; task = null; @@ -1027,7 +1034,10 @@ bool CheckActivationReason(ref Task task, MonitorActivationReason testActivation { Logger.LogTrace("Detaching server..."); var controller = GetActiveController(); - await controller.Release(); + if (controller != null) + await controller.Release(); + else + Logger.LogError("Controller was null on monitor shutdown!"); } } @@ -1091,6 +1101,9 @@ async ValueTask HandleHealthCheck(CancellationToken cancellationT { Logger.LogTrace("Sending health check to active server..."); var activeServer = GetActiveController(); + if (activeServer == null) + return MonitorAction.Restart; // uhhhh??? + var response = await activeServer.SendCommand(new TopicParameters(), cancellationToken); var shouldShutdown = activeServer.RebootState == Session.RebootState.Shutdown; @@ -1130,7 +1143,7 @@ async ValueTask HandleHealthCheck(CancellationToken cancellationT actionTaken, StringComparison.Ordinal)); - if (ActiveLaunchParameters.DumpOnHealthCheckRestart.Value) + if (ActiveLaunchParameters.DumpOnHealthCheckRestart!.Value) { Logger.LogDebug("DumpOnHealthCheckRestart enabled."); try @@ -1166,13 +1179,30 @@ async ValueTask HandleHealthCheck(CancellationToken cancellationT /// Handle any in a given topic . /// /// The . - void HandleChatResponses(TopicResponse result) + void HandleChatResponses(TopicResponse? result) { if (result?.ChatResponses != null) - foreach (var response in result.ChatResponses) + { + var warnedMissingChannelIds = false; + foreach (var response in result.ChatResponses + .Where(response => + { + if (response.ChannelIds == null) + { + if (!warnedMissingChannelIds) + { + Logger.LogWarning("DMAPI response contains null channelIds!"); + warnedMissingChannelIds = true; + } + + return false; + } + + return true; + })) Chat.QueueMessage( response, - response.ChannelIds + response.ChannelIds! .Select(channelIdString => { if (UInt64.TryParse(channelIdString, out var channelId)) @@ -1183,7 +1213,8 @@ void HandleChatResponses(TopicResponse result) return null; }) .Where(nullableChannelId => nullableChannelId.HasValue) - .Select(nullableChannelId => nullableChannelId.Value)); + .Select(nullableChannelId => nullableChannelId!.Value)); + } } /// From e99cb6ba4054e2785de3b27a5ab09b2ed701cd0e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 24 Dec 2023 08:46:56 -0500 Subject: [PATCH 715/717] Revert "Setup GitHub actions for V6 branch" This reverts commit baa908f0b2858a09da16642f8dd44f4849a7d9e6. --- .../workflows/auto-approve-dominions-prs.yml | 1 - .github/workflows/ci-pipeline.yml | 3 -- .github/workflows/code-scanning.yml | 2 -- .github/workflows/v6-integration.yml | 29 ------------------- 4 files changed, 35 deletions(-) delete mode 100644 .github/workflows/v6-integration.yml diff --git a/.github/workflows/auto-approve-dominions-prs.yml b/.github/workflows/auto-approve-dominions-prs.yml index 53546b6f667..cd499fffde8 100644 --- a/.github/workflows/auto-approve-dominions-prs.yml +++ b/.github/workflows/auto-approve-dominions-prs.yml @@ -8,7 +8,6 @@ on: branches: - dev - master - - V6 concurrency: group: "approve-dominion-${{ github.head_ref || github.run_id }}-${{ github.event_name }}" diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 483a030d505..bad76f3ba3a 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -25,18 +25,15 @@ on: branches: - dev - master - - V6 pull_request: branches: - dev - master - - V6 pull_request_target: types: [ opened, reopened, labeled, synchronize ] branches: - dev - master - - V6 env: TGS_DOTNET_VERSION: 8 diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml index a7baad0e0eb..b6610591447 100644 --- a/.github/workflows/code-scanning.yml +++ b/.github/workflows/code-scanning.yml @@ -5,12 +5,10 @@ on: branches: - dev - master - - V6 pull_request: branches: - dev - master - - V6 env: TGS_DOTNET_VERSION: 8 diff --git a/.github/workflows/v6-integration.yml b/.github/workflows/v6-integration.yml deleted file mode 100644 index 83be1561eb4..00000000000 --- a/.github/workflows/v6-integration.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: 'V6 Integration' - -on: - push: - branches: - - dev - -jobs: - v6-integration: - - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v1 - - - name: Merge dev into V6 - uses: robotology/gh-action-nightly-merge@22f5e45d028f22837d617fa07512925457eec184 #v1.3.3 - with: - stable_branch: 'dev' - development_branch: 'V6' - allow_ff: true - allow_forks: true - user_name: tgstation-server - user_email: tgstation-server@users.noreply.github.com - push_token: DEV_PUSH_TOKEN - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DEV_PUSH_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }} From d87ed2c39041e784fc20641af46a5b5c1274511b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 24 Dec 2023 08:51:36 -0500 Subject: [PATCH 716/717] Remove and additional `V6` branch reference in CI --- .github/workflows/check-pr-has-milestone.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/check-pr-has-milestone.yml b/.github/workflows/check-pr-has-milestone.yml index 7f6ed97d2d7..0ce8c605f99 100644 --- a/.github/workflows/check-pr-has-milestone.yml +++ b/.github/workflows/check-pr-has-milestone.yml @@ -6,7 +6,6 @@ on: branches: - dev - master - - V6 concurrency: group: "check-pr-milestone-${{ github.head_ref || github.run_id }}-${{ github.event_name }}" From e5a7ec6556bb839317daf8826a26b71799269b25 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 24 Dec 2023 11:08:07 -0500 Subject: [PATCH 717/717] Update webpanel version to 5.3.0 --- build/WebpanelVersion.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/WebpanelVersion.props b/build/WebpanelVersion.props index 3e3a8aa08cb..8b9090a8059 100644 --- a/build/WebpanelVersion.props +++ b/build/WebpanelVersion.props @@ -1,6 +1,6 @@ - 5.1.0 + 5.3.0