mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-23 21:16:52 +01:00
Setup dependency injection for mapping IEngineInstallers and global OD repo manager
Various other things to get it compiling
This commit is contained in:
@@ -25,6 +25,7 @@ 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.Configuration;
|
||||
using Tgstation.Server.Host.Extensions;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
using Tgstation.Server.Host.Models;
|
||||
@@ -69,6 +70,11 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
/// </summary>
|
||||
readonly IAssemblyInformationProvider assemblyInformationProvider;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="GeneralConfiguration"/> for the <see cref="DiscordProvider"/>.
|
||||
/// </summary>
|
||||
readonly GeneralConfiguration generalConfiguration;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ServiceProvider"/> containing Discord services.
|
||||
/// </summary>
|
||||
@@ -126,63 +132,6 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
/// <returns>The normalized mention <see cref="string"/>.</returns>
|
||||
static string NormalizeMentions(string fromDiscord) => fromDiscord.Replace("<@!", "<@", StringComparison.Ordinal);
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="List{T}"/> of <see cref="IEmbedField"/>s for a discord update embed.
|
||||
/// </summary>
|
||||
/// <param name="revisionInformation">The <see cref="RevisionInformation"/> of the deployment.</param>
|
||||
/// <param name="byondVersion">The <see cref="ByondVersion"/> of the deployment.</param>
|
||||
/// <param name="gitHubOwner">The repository GitHub owner, if any.</param>
|
||||
/// <param name="gitHubRepo">The repository GitHub name, if any.</param>
|
||||
/// <param name="localCommitPushed"><see langword="true"/> if the local deployment commit was pushed to the remote repository.</param>
|
||||
/// <returns>A new <see cref="List{T}"/> of <see cref="IEmbedField"/>s to use.</returns>
|
||||
static List<IEmbedField> 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<IEmbedField>
|
||||
{
|
||||
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<RevInfoTestMerge>())
|
||||
.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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DiscordProvider"/> class.
|
||||
/// </summary>
|
||||
@@ -191,15 +140,18 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="Provider"/>.</param>
|
||||
/// <param name="assemblyInformationProvider">The value of <see cref="assemblyInformationProvider"/>.</param>
|
||||
/// <param name="chatBot">The <see cref="ChatBot"/> for the <see cref="Provider"/>.</param>
|
||||
/// <param name="generalConfiguration">The value of <see cref="generalConfiguration"/>.</param>
|
||||
public DiscordProvider(
|
||||
IJobManager jobManager,
|
||||
IAsyncDelayer asyncDelayer,
|
||||
ILogger<DiscordProvider> 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<ulong>();
|
||||
connectDisconnectLock = new object();
|
||||
@@ -903,12 +855,69 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
return allAccessibleChannels;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="List{T}"/> of <see cref="IEmbedField"/>s for a discord update embed.
|
||||
/// </summary>
|
||||
/// <param name="revisionInformation">The <see cref="RevisionInformation"/> of the deployment.</param>
|
||||
/// <param name="byondVersion">The <see cref="ByondVersion"/> of the deployment.</param>
|
||||
/// <param name="gitHubOwner">The repository GitHub owner, if any.</param>
|
||||
/// <param name="gitHubRepo">The repository GitHub name, if any.</param>
|
||||
/// <param name="localCommitPushed"><see langword="true"/> if the local deployment commit was pushed to the remote repository.</param>
|
||||
/// <returns>A new <see cref="List{T}"/> of <see cref="IEmbedField"/>s to use.</returns>
|
||||
List<IEmbedField> 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<IEmbedField>
|
||||
{
|
||||
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<RevInfoTestMerge>())
|
||||
.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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a <see cref="ChatEmbed"/> to an <see cref="IEmbed"/> parameters.
|
||||
/// </summary>
|
||||
/// <param name="embed">The <see cref="ChatEmbed"/> to convert.</param>
|
||||
/// <returns>The parameter for sending a single <see cref="IEmbed"/>.</returns>
|
||||
#pragma warning disable CA1502
|
||||
#pragma warning disable CA1502
|
||||
Optional<IReadOnlyList<IEmbed>> ConvertEmbed(ChatEmbed embed)
|
||||
{
|
||||
if (embed == null)
|
||||
|
||||
@@ -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 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
/// </summary>
|
||||
readonly ILoggerFactory loggerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="GeneralConfiguration"/> for the <see cref="ProviderFactory"/>.
|
||||
/// </summary>
|
||||
readonly GeneralConfiguration generalConfiguration;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProviderFactory"/> class.
|
||||
/// </summary>
|
||||
@@ -40,16 +47,19 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
/// <param name="assemblyInformationProvider">The value of <see cref="assemblyInformationProvider"/>.</param>
|
||||
/// <param name="asyncDelayer">The value of <see cref="asyncDelayer"/>.</param>
|
||||
/// <param name="loggerFactory">The value of <see cref="loggerFactory"/>.</param>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the value of <see cref="generalConfiguration"/>.</param>
|
||||
public ProviderFactory(
|
||||
IJobManager jobManager,
|
||||
IAssemblyInformationProvider assemblyInformationProvider,
|
||||
IAsyncDelayer asyncDelayer,
|
||||
ILoggerFactory loggerFactory)
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<GeneralConfiguration> 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));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -69,7 +79,8 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
asyncDelayer,
|
||||
loggerFactory.CreateLogger<DiscordProvider>(),
|
||||
assemblyInformationProvider,
|
||||
settings),
|
||||
settings,
|
||||
generalConfiguration),
|
||||
_ => throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid ChatProvider: {0}", settings.Provider)),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -864,39 +864,29 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
async ValueTask<bool> 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);
|
||||
await using var dm = processExecutor.LaunchProcess(
|
||||
engineLock.CompilerExePath,
|
||||
ioManager.ResolvePath(
|
||||
job.DirectoryName.ToString()),
|
||||
arguments,
|
||||
readStandardHandles: true,
|
||||
noShellExecute: true);
|
||||
|
||||
int exitCode;
|
||||
using (cancellationToken.Register(() => dm.Terminate()))
|
||||
exitCode = (await dm.Lifetime).Value;
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (sessionConfiguration.LowPriorityDeploymentProcesses)
|
||||
dm.AdjustPriority(false);
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="IEngineInstaller"/> that forwards calls to different <see cref="IEngineInstaller"/> based on their appropriate <see cref="EngineType"/>.
|
||||
/// </summary>
|
||||
sealed class DelegatingEngineInstaller : IEngineInstaller
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="IReadOnlyDictionary{TKey, TValue}"/> mapping <see cref="EngineType"/>s to their appropriate <see cref="IEngineInstaller"/>.
|
||||
/// </summary>
|
||||
readonly IReadOnlyDictionary<EngineType, IEngineInstaller> delegatedInstallers;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DelegatingEngineInstaller"/> class.
|
||||
/// </summary>
|
||||
/// <param name="delegatedInstallers">The value of <see cref="delegatedInstallers"/>.</param>
|
||||
public DelegatingEngineInstaller(IReadOnlyDictionary<EngineType, IEngineInstaller> delegatedInstallers)
|
||||
{
|
||||
this.delegatedInstallers = delegatedInstallers ?? throw new ArgumentNullException(nameof(delegatedInstallers));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task CleanCache(CancellationToken cancellationToken)
|
||||
=> Task.WhenAll(delegatedInstallers.Values.Select(installer => installer.CleanCache(cancellationToken)));
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask)
|
||||
=> DelegateCall(version, installer => installer.CreateInstallation(version, installationTask));
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask<IEngineInstallationData> DownloadVersion(ByondVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken)
|
||||
=> DelegateCall(version, installer => installer.DownloadVersion(version, jobProgressReporter, cancellationToken));
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask Install(ByondVersion version, string path, CancellationToken cancellationToken)
|
||||
=> DelegateCall(version, installer => installer.Install(version, path, cancellationToken));
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken)
|
||||
=> ValueTaskExtensions.WhenAll(delegatedInstallers.Values.Select(installer => installer.TrustDmbPath(fullDmbPath, cancellationToken)));
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask UpgradeInstallation(ByondVersion version, string path, CancellationToken cancellationToken)
|
||||
=> DelegateCall(version, installer => installer.UpgradeInstallation(version, path, cancellationToken));
|
||||
|
||||
/// <summary>
|
||||
/// Delegate a given <paramref name="call"/> to its appropriate <see cref="IEngineInstaller"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TReturn">The return <see cref="Type"/> of the call.</typeparam>
|
||||
/// <param name="version">The <see cref="ByondVersion"/> used to perform delegate selection.</param>
|
||||
/// <param name="call">The <see cref="Func{T, TResult}"/> that will be called with the correct <see cref="IEngineInstaller"/> based on <paramref name="version"/>.</param>
|
||||
/// <returns>The <typeparamref name="TReturn"/> value of the delegated call.</returns>
|
||||
TReturn DelegateCall<TReturn>(ByondVersion version, Func<IEngineInstaller, TReturn> call)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(version);
|
||||
return call(delegatedInstallers[version.Engine.Value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// Return the command line arguments for compiling a given <paramref name="dmePath"/> if compilation is necessary.
|
||||
/// </summary>
|
||||
/// <param name="dmePath">The full path to the .dme to compile.</param>
|
||||
/// <returns>An arguments <see cref="string"/> if compilation is required, <see langword="null"/> otherwise.</returns>
|
||||
/// <returns>The formatted arguments <see cref="string"/>.</returns>
|
||||
string FormatCompilerArguments(string dmePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,10 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <inheritdoc />
|
||||
public string FormatServerArguments(IDmbProvider dmbProvider, IReadOnlyDictionary<string, string> parameters, DreamDaemonLaunchParameters launchParameters, string logFilePath)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dmbProvider);
|
||||
ArgumentNullException.ThrowIfNull(parameters);
|
||||
ArgumentNullException.ThrowIfNull(launchParameters);
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -61,7 +65,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
public string FormatCompilerArguments(string dmePath)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dmePath);
|
||||
return null;
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.Common;
|
||||
using Tgstation.Server.Host.Components.Repository;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
@@ -120,14 +121,20 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
|
||||
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
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// No-op implementation of <see cref="IEventConsumer"/>.
|
||||
/// </summary>
|
||||
sealed class NoopEventConsumer : IEventConsumer
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ValueTask HandleEvent(EventType eventType, IEnumerable<string> parameters, bool deploymentPipeline, CancellationToken cancellationToken)
|
||||
=> ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -111,14 +111,9 @@ namespace Tgstation.Server.Host.Components
|
||||
readonly IPlatformIdentifier platformIdentifier;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILibGit2RepositoryFactory"/> for the <see cref="InstanceFactory"/>.
|
||||
/// The <see cref="IRepositoryManagerFactory"/> for the <see cref=" InstanceFactory"/>.
|
||||
/// </summary>
|
||||
readonly ILibGit2RepositoryFactory repositoryFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILibGit2Commands"/> for the <see cref="InstanceFactory"/>.
|
||||
/// </summary>
|
||||
readonly ILibGit2Commands repositoryCommands;
|
||||
readonly IRepositoryManagerFactory repositoryManagerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IServerPortProvider"/> for the <see cref="InstanceFactory"/>.
|
||||
@@ -130,11 +125,6 @@ namespace Tgstation.Server.Host.Components
|
||||
/// </summary>
|
||||
readonly IFileTransferTicketProvider fileTransferService;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IGitRemoteFeaturesFactory"/> for the <see cref="InstanceFactory"/>.
|
||||
/// </summary>
|
||||
readonly IGitRemoteFeaturesFactory gitRemoteFeaturesFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IRemoteDeploymentManagerFactory"/> for the <see cref="InstanceFactory"/>.
|
||||
/// </summary>
|
||||
@@ -182,11 +172,9 @@ namespace Tgstation.Server.Host.Components
|
||||
/// <param name="jobManager">The value of <see cref="jobManager"/>.</param>
|
||||
/// <param name="networkPromptReaper">The value of <see cref="networkPromptReaper"/>.</param>
|
||||
/// <param name="platformIdentifier">The value of <see cref="platformIdentifier"/>.</param>
|
||||
/// <param name="repositoryFactory">The value of <see cref="repositoryFactory"/>.</param>
|
||||
/// <param name="repositoryCommands">The value of <see cref="repositoryCommands"/>.</param>
|
||||
/// <param name="repositoryManagerFactory">The value of <see cref="repositoryManagerFactory"/>.</param>
|
||||
/// <param name="serverPortProvider">The value of <see cref="serverPortProvider"/>.</param>
|
||||
/// <param name="fileTransferService">The value of <see cref="fileTransferService"/>.</param>
|
||||
/// <param name="gitRemoteFeaturesFactory">The value of <see cref="gitRemoteFeaturesFactory"/>.</param>
|
||||
/// <param name="remoteDeploymentManagerFactory">The value of <see cref="remoteDeploymentManagerFactory"/>.</param>
|
||||
/// <param name="asyncDelayer">The value of <see cref="asyncDelayer"/>.</param>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the value of <see cref="generalConfiguration"/>.</param>
|
||||
@@ -208,11 +196,9 @@ namespace Tgstation.Server.Host.Components
|
||||
IJobManager jobManager,
|
||||
INetworkPromptReaper networkPromptReaper,
|
||||
IPlatformIdentifier platformIdentifier,
|
||||
ILibGit2RepositoryFactory repositoryFactory,
|
||||
ILibGit2Commands repositoryCommands,
|
||||
IRepositoryManagerFactory repositoryManagerFactory,
|
||||
IServerPortProvider serverPortProvider,
|
||||
IFileTransferTicketProvider fileTransferService,
|
||||
IGitRemoteFeaturesFactory gitRemoteFeaturesFactory,
|
||||
IRemoteDeploymentManagerFactory remoteDeploymentManagerFactory,
|
||||
IAsyncDelayer asyncDelayer,
|
||||
IOptions<GeneralConfiguration> generalConfigurationOptions,
|
||||
@@ -234,11 +220,9 @@ namespace Tgstation.Server.Host.Components
|
||||
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 @@ namespace Tgstation.Server.Host.Components
|
||||
generalConfiguration,
|
||||
sessionConfiguration);
|
||||
var eventConsumer = new EventConsumer(configuration);
|
||||
var repoManager = new RepositoryManager(
|
||||
repositoryFactory,
|
||||
repositoryCommands,
|
||||
repoIoManager,
|
||||
eventConsumer,
|
||||
postWriteHandler,
|
||||
gitRemoteFeaturesFactory,
|
||||
loggerFactory.CreateLogger<Repository.Repository>(),
|
||||
loggerFactory.CreateLogger<RepositoryManager>(),
|
||||
generalConfiguration);
|
||||
var repoManager = repositoryManagerFactory.CreateRepositoryManager(repoIoManager, eventConsumer);
|
||||
try
|
||||
{
|
||||
var byond = new EngineManager(byondIOManager, engineInstaller, eventConsumer, loggerFactory.CreateLogger<EngineManager>());
|
||||
var engineManager = new EngineManager(byondIOManager, engineInstaller, eventConsumer, loggerFactory.CreateLogger<EngineManager>());
|
||||
|
||||
var dmbFactory = new DmbFactory(
|
||||
databaseContextFactory,
|
||||
@@ -307,7 +282,7 @@ namespace Tgstation.Server.Host.Components
|
||||
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 @@ namespace Tgstation.Server.Host.Components
|
||||
|
||||
var sessionControllerFactory = new SessionControllerFactory(
|
||||
processExecutor,
|
||||
byond,
|
||||
engineManager,
|
||||
topicClientFactory,
|
||||
cryptographySuite,
|
||||
assemblyInformationProvider,
|
||||
@@ -357,7 +332,7 @@ namespace Tgstation.Server.Host.Components
|
||||
|
||||
Instance instance = null;
|
||||
var dreamMaker = new DreamMaker(
|
||||
byond,
|
||||
engineManager,
|
||||
gameIoManager,
|
||||
configuration,
|
||||
sessionControllerFactory,
|
||||
@@ -375,7 +350,7 @@ namespace Tgstation.Server.Host.Components
|
||||
instance = new Instance(
|
||||
metadata,
|
||||
repoManager,
|
||||
byond,
|
||||
engineManager,
|
||||
dreamMaker,
|
||||
watchdog,
|
||||
chatManager,
|
||||
@@ -417,18 +392,12 @@ namespace Tgstation.Server.Host.Components
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
CheckSystemCompatibility();
|
||||
return engineInstaller.CleanCache(cancellationToken);
|
||||
}
|
||||
=> Task.WhenAll(
|
||||
repositoryManagerFactory.StartAsync(cancellationToken),
|
||||
engineInstaller.CleanCache(cancellationToken));
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Test that the <see cref="repositoryFactory"/> is functional.
|
||||
/// </summary>
|
||||
void CheckSystemCompatibility() => repositoryFactory.CreateInMemory();
|
||||
public Task StopAsync(CancellationToken cancellationToken) => repositoryManagerFactory.StopAsync(cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Create the <see cref="IIOManager"/> for a given set of instance <paramref name="metadata"/>.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using Tgstation.Server.Host.Components.Events;
|
||||
using Tgstation.Server.Host.IO;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Repository
|
||||
{
|
||||
/// <summary>
|
||||
/// Factory for creating <see cref="IRepositoryManager"/>s.
|
||||
/// </summary>
|
||||
interface IRepositoryManagerFactory : IComponentService
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a <see cref="IRepositoryManager"/>.
|
||||
/// </summary>
|
||||
/// <param name="ioManager">The <see cref="IIOManager"/> to use.</param>
|
||||
/// <param name="eventConsumer">The <see cref="IEventConsumer"/> to use.</param>
|
||||
/// <returns>A new <see cref="IRepositoryManager"/>.</returns>
|
||||
IRepositoryManager CreateRepositoryManager(IIOManager ioManager, IEventConsumer eventConsumer);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <inheritdoc />
|
||||
sealed class RepostoryManagerFactory : IRepositoryManagerFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="ILibGit2RepositoryFactory"/> for the <see cref="RepostoryManagerFactory"/>.
|
||||
/// </summary>
|
||||
readonly ILibGit2RepositoryFactory repositoryFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILibGit2Commands"/> for the <see cref="RepostoryManagerFactory"/>.
|
||||
/// </summary>
|
||||
readonly ILibGit2Commands repositoryCommands;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IPostWriteHandler"/> for the <see cref="RepostoryManagerFactory"/>.
|
||||
/// </summary>
|
||||
readonly IPostWriteHandler postWriteHandler;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IGitRemoteFeaturesFactory"/> for the <see cref="RepostoryManagerFactory"/>.
|
||||
/// </summary>
|
||||
readonly IGitRemoteFeaturesFactory gitRemoteFeaturesFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILoggerFactory"/> for the <see cref="RepostoryManagerFactory"/>.
|
||||
/// </summary>
|
||||
readonly ILoggerFactory loggerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="GeneralConfiguration"/> for the <see cref="RepostoryManagerFactory"/>.
|
||||
/// </summary>
|
||||
readonly GeneralConfiguration generalConfiguration;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RepostoryManagerFactory"/> class.
|
||||
/// </summary>
|
||||
/// <param name="repositoryFactory">The value of <see cref="repositoryFactory"/>.</param>
|
||||
/// <param name="repositoryCommands">The value of <see cref="repositoryCommands"/>.</param>
|
||||
/// <param name="postWriteHandler">The value of <see cref="postWriteHandler"/>.</param>
|
||||
/// <param name="gitRemoteFeaturesFactory">The value of <see cref="gitRemoteFeaturesFactory"/>.</param>
|
||||
/// <param name="loggerFactory">The value of <see cref="loggerFactory"/>.</param>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the value of <see cref="generalConfiguration"/>.</param>
|
||||
public RepostoryManagerFactory(
|
||||
ILibGit2RepositoryFactory repositoryFactory,
|
||||
ILibGit2Commands repositoryCommands,
|
||||
IPostWriteHandler postWriteHandler,
|
||||
IGitRemoteFeaturesFactory gitRemoteFeaturesFactory,
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<GeneralConfiguration> 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));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IRepositoryManager CreateRepositoryManager(IIOManager ioManager, IEventConsumer eventConsumer)
|
||||
=> new RepositoryManager(
|
||||
repositoryFactory,
|
||||
repositoryCommands,
|
||||
ioManager,
|
||||
eventConsumer,
|
||||
postWriteHandler,
|
||||
gitRemoteFeaturesFactory,
|
||||
loggerFactory.CreateLogger<Repository>(),
|
||||
loggerFactory.CreateLogger<RepositoryManager>(),
|
||||
generalConfiguration);
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
CheckSystemCompatibility();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Test that the <see cref="repositoryFactory"/> is functional.
|
||||
/// </summary>
|
||||
void CheckSystemCompatibility() => repositoryFactory.CreateInMemory();
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,11 @@ namespace Tgstation.Server.Host.Configuration
|
||||
/// </summary>
|
||||
const string DefaultOpenDreamGitUrl = "https://github.com/OpenDreamProject/OpenDream";
|
||||
|
||||
/// <summary>
|
||||
/// The default value for <see cref="OpenDreamGitTagPrefix"/>.
|
||||
/// </summary>
|
||||
const string DefaultOpenDreamGitTagPrefix = "v";
|
||||
|
||||
/// <summary>
|
||||
/// The current <see cref="ConfigVersion"/>.
|
||||
/// </summary>
|
||||
@@ -132,6 +137,11 @@ namespace Tgstation.Server.Host.Configuration
|
||||
/// </summary>
|
||||
public Uri OpenDreamGitUrl { get; set; } = new Uri(DefaultOpenDreamGitUrl);
|
||||
|
||||
/// <summary>
|
||||
/// The prefix to the OpenDream semver as tags appear in the git repository.
|
||||
/// </summary>
|
||||
public string OpenDreamGitTagPrefix { get; set; } = DefaultOpenDreamGitTagPrefix;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GeneralConfiguration"/> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
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 @@ namespace Tgstation.Server.Host.Controllers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the active <see cref="Api.Models.Internal.ByondVersion"/>.
|
||||
/// Gets the active <see cref="ByondVersion"/>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the <see cref="IActionResult"/> for the operation.</returns>
|
||||
/// <response code="200">Retrieved version information successfully.</response>
|
||||
@@ -91,7 +92,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
: Conflict(new ErrorMessageResponse(ErrorCode.ResourceNotPresent))));
|
||||
|
||||
/// <summary>
|
||||
/// Lists installed <see cref="Api.Models.Internal.ByondVersion"/>s.
|
||||
/// Lists installed <see cref="ByondVersion"/>s.
|
||||
/// </summary>
|
||||
/// <param name="page">The current page.</param>
|
||||
/// <param name="pageSize">The page size.</param>
|
||||
@@ -139,15 +140,11 @@ namespace Tgstation.Server.Host.Controllers
|
||||
#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 @@ namespace Tgstation.Server.Host.Controllers
|
||||
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 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the <see cref="IActionResult"/> for the operation.</returns>
|
||||
/// <response code="202">Created <see cref="Job"/> to delete target version successfully.</response>
|
||||
/// <response code="409">Attempted to delete the active BYOND <see cref="Version"/>.</response>
|
||||
/// <response code="410">The <see cref="Api.Models.Internal.ByondVersion"/> specified was not installed.</response>
|
||||
/// <response code="410">The <see cref="ByondVersion"/> specified was not installed.</response>
|
||||
[HttpDelete]
|
||||
[TgsAuthorize(ByondRights.DeleteInstall)]
|
||||
[ProducesResponseType(typeof(JobResponse), 202)]
|
||||
@@ -279,13 +276,9 @@ namespace Tgstation.Server.Host.Controllers
|
||||
[ProducesResponseType(typeof(ErrorMessageResponse), 410)]
|
||||
public async ValueTask<IActionResult> 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 @@ namespace Tgstation.Server.Host.Controllers
|
||||
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 @@ namespace Tgstation.Server.Host.Controllers
|
||||
var apiResponse = job.ToApi();
|
||||
return Accepted(apiResponse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate and normalize a given <paramref name="version"/>.
|
||||
/// </summary>
|
||||
/// <param name="version">The <see cref="ByondVersion"/> to validate and normalize.</param>
|
||||
/// <returns>The <see cref="BadRequestObjectResult"/> to return, if any.</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,13 @@ using Serilog.Formatting.Display;
|
||||
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 @@ namespace Tgstation.Server.Host.Core
|
||||
AddWatchdog<WindowsWatchdogFactory>(services, postSetupServices);
|
||||
services.AddSingleton<ISystemIdentityFactory, WindowsSystemIdentityFactory>();
|
||||
services.AddSingleton<ISymlinkFactory, WindowsSymlinkFactory>();
|
||||
services.AddSingleton<IEngineInstaller, WindowsByondInstaller>();
|
||||
services.AddSingleton<ByondInstallerBase, WindowsByondInstaller>();
|
||||
services.AddSingleton<IPostWriteHandler, WindowsPostWriteHandler>();
|
||||
services.AddSingleton<IProcessFeatures, WindowsProcessFeatures>();
|
||||
|
||||
@@ -345,7 +347,7 @@ namespace Tgstation.Server.Host.Core
|
||||
AddWatchdog<PosixWatchdogFactory>(services, postSetupServices);
|
||||
services.AddSingleton<ISystemIdentityFactory, PosixSystemIdentityFactory>();
|
||||
services.AddSingleton<ISymlinkFactory, PosixSymlinkFactory>();
|
||||
services.AddSingleton<IEngineInstaller, PosixByondInstaller>();
|
||||
services.AddSingleton<ByondInstallerBase, PosixByondInstaller>();
|
||||
services.AddSingleton<IPostWriteHandler, PosixPostWriteHandler>();
|
||||
|
||||
services.AddSingleton<IProcessFeatures, PosixProcessFeatures>();
|
||||
@@ -357,6 +359,29 @@ namespace Tgstation.Server.Host.Core
|
||||
services.AddHostedService<PosixSignalHandler>();
|
||||
}
|
||||
|
||||
// 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<IRepositoryManagerFactory>()
|
||||
.CreateRepositoryManager(
|
||||
new ResolvingIOManager(
|
||||
services.GetRequiredService<IIOManager>(),
|
||||
openDreamRepositoryDirectory),
|
||||
new NoopEventConsumer()));
|
||||
|
||||
services.AddSingleton<OpenDreamInstaller>();
|
||||
services.AddSingleton(
|
||||
serviceProvider => new Dictionary<EngineType, IEngineInstaller>
|
||||
{
|
||||
{ EngineType.Byond, serviceProvider.GetRequiredService<ByondInstallerBase>() },
|
||||
{ EngineType.OpenDream, serviceProvider.GetRequiredService<OpenDreamInstaller>() },
|
||||
});
|
||||
services.AddSingleton<IEngineInstaller, DelegatingEngineInstaller>();
|
||||
|
||||
if (postSetupServices.InternalConfiguration.UsingSystemD)
|
||||
services.AddHostedService<SystemDManager>();
|
||||
|
||||
@@ -378,6 +403,7 @@ namespace Tgstation.Server.Host.Core
|
||||
services.AddSingleton<IGitRemoteFeaturesFactory, GitRemoteFeaturesFactory>();
|
||||
services.AddSingleton<ILibGit2RepositoryFactory, LibGit2RepositoryFactory>();
|
||||
services.AddSingleton<ILibGit2Commands, LibGit2Commands>();
|
||||
services.AddSingleton<IRepositoryManagerFactory, RepostoryManagerFactory>();
|
||||
services.AddSingleton<IRemoteDeploymentManagerFactory, RemoteDeploymentManagerFactory>();
|
||||
services.AddChatProviderFactory();
|
||||
services.AddSingleton<IChatManagerFactory, ChatManagerFactory>();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,6 +8,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
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 @@ namespace Tgstation.Server.Host.Components.Chat.Providers.Tests
|
||||
ReconnectionInterval = 1,
|
||||
};
|
||||
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new DiscordProvider(null, null, null, null, null));
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new DiscordProvider(mockJobManager, null, null, null, null));
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new DiscordProvider(null, null, null, null, null, null));
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new DiscordProvider(mockJobManager, null, null, null, null, null));
|
||||
var mockDel = Mock.Of<IAsyncDelayer>();
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new DiscordProvider(mockJobManager, mockDel, null, null, null));
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new DiscordProvider(mockJobManager, mockDel, null, null, null, null));
|
||||
var mockLogger = Mock.Of<ILogger<DiscordProvider>>();
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new DiscordProvider(mockJobManager, mockDel, mockLogger, null, null));
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new DiscordProvider(mockJobManager, mockDel, mockLogger, null, null, null));
|
||||
var mockAss = Mock.Of<IAssemblyInformationProvider>();
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new DiscordProvider(mockJobManager, mockDel, mockLogger, mockAss, null));
|
||||
await new DiscordProvider(mockJobManager, mockDel, mockLogger, mockAss, bot).DisposeAsync();
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new DiscordProvider(mockJobManager, mockDel, mockLogger, mockAss, null, null));
|
||||
Assert.ThrowsException<ArgumentNullException>(() => 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 @@ namespace Tgstation.Server.Host.Components.Chat.Providers.Tests
|
||||
{
|
||||
ReconnectionInterval = 1,
|
||||
ConnectionString = "asdf"
|
||||
});
|
||||
}, new GeneralConfiguration());
|
||||
await Assert.ThrowsExceptionAsync<JobException>(async () => await InvokeConnect(provider));
|
||||
Assert.IsFalse(provider.Connected);
|
||||
}
|
||||
@@ -88,7 +91,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers.Tests
|
||||
Assert.Fail("TGS_TEST_DISCORD_TOKEN is not a valid Discord connection string!");
|
||||
|
||||
var mockLogger = new Mock<ILogger<DiscordProvider>>();
|
||||
await using var provider = new DiscordProvider(mockJobManager, Mock.Of<IAsyncDelayer>(), mockLogger.Object, Mock.Of<IAssemblyInformationProvider>(), testToken1);
|
||||
await using var provider = new DiscordProvider(mockJobManager, Mock.Of<IAsyncDelayer>(), mockLogger.Object, Mock.Of<IAssemblyInformationProvider>(), testToken1, new GeneralConfiguration());
|
||||
Assert.IsFalse(provider.Connected);
|
||||
await InvokeConnect(provider);
|
||||
Assert.IsTrue(provider.Connected);
|
||||
|
||||
Reference in New Issue
Block a user