mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-27 07:04:57 +01:00
Merge pull request #1435 from tgstation/FeatureBranch
Discord Replies and some other stuff
This commit is contained in:
@@ -218,7 +218,7 @@ For the docker version run `docker stop <your container name>`
|
||||
|
||||
## Integrating
|
||||
|
||||
tgstation-server 4 provides the DMAPI which can be be integrated into any BYOND codebase for heavily enhanced functionality. The integration process is a fairly simple set of code changes.
|
||||
tgstation-server provides the DMAPI which can be be integrated into any BYOND codebase for heavily enhanced functionality. The integration process is a fairly simple set of code changes.
|
||||
|
||||
1. Copy the [latest release of the DMAPI](https://github.com/tgstation/tgstation-server/releases) anywhere in your code base. `tgs.dm` can be seperated from the `tgs` folder, but do not modify or move the contents of the `tgs` folder
|
||||
2. Modify your `.dme`(s) to include the `tgs.dm` and `tgs/includes.dm` files (ORDER OF APPEARANCE IS MANDATORY)
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<!-- Integration tests will ensure they match across the board -->
|
||||
<Import Project="ControlPanelVersion.props" />
|
||||
<PropertyGroup>
|
||||
<TgsCoreVersion>5.3.3</TgsCoreVersion>
|
||||
<TgsCoreVersion>5.4.0</TgsCoreVersion>
|
||||
<TgsConfigVersion>4.4.0</TgsConfigVersion>
|
||||
<TgsApiVersion>9.8.1</TgsApiVersion>
|
||||
<TgsApiLibraryVersion>10.2.0</TgsApiLibraryVersion>
|
||||
|
||||
@@ -22,8 +22,10 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
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
|
||||
_ => throw new InvalidOperationException("Invalid provider type!"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.2.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -26,15 +26,11 @@ namespace Tgstation.Server.Host.Console
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
internal static async Task Main(string[] args)
|
||||
{
|
||||
using var loggerFactory = new LoggerFactory();
|
||||
using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
|
||||
var arguments = new List<string>(args);
|
||||
var trace = arguments.Remove("--trace-host-watchdog");
|
||||
var debug = arguments.Remove("--debug-host-watchdog");
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
loggerFactory.AddConsole();
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
if (trace && debug)
|
||||
{
|
||||
loggerFactory.CreateLogger(nameof(Program)).LogCritical("Please specify only 1 of --trace-host-watchdog or --debug-host-watchdog!");
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<!-- DO NOT UPDATE UNLESS YOU WANT TO DEAL WITH THE LOGGERFACTORY REFACTOR -->
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
|
||||
@@ -77,6 +77,54 @@ namespace Tgstation.Server.Host.Service
|
||||
/// <returns>A <see cref="Task"/> resulting in the <see cref="Program"/>'s exit code.</returns>
|
||||
static Task<int> Main(string[] args) => CommandLineApplication.ExecuteAsync<Program>(args);
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to install the TGS Service.
|
||||
/// </summary>
|
||||
static void RunServiceInstall()
|
||||
{
|
||||
// First check if the service already exists
|
||||
if (Environment.UserInteractive)
|
||||
foreach (ServiceController sc in ServiceController.GetServices())
|
||||
if (sc.ServiceName == "tgstation-server" || sc.ServiceName == "tgstation-server-4")
|
||||
{
|
||||
DialogResult result = MessageBox.Show($"You already have another TGS service installed ({sc.ServiceName}). Would you like to uninstall it now? Pressing \"No\" will cancel this install.", "TGS Service", MessageBoxButtons.YesNo);
|
||||
if (result != DialogResult.Yes)
|
||||
return; // is this needed after exit?
|
||||
|
||||
// Stop it first to give it some cleanup time
|
||||
if (sc.Status == ServiceControllerStatus.Running)
|
||||
{
|
||||
sc.Stop();
|
||||
sc.WaitForStatus(ServiceControllerStatus.Stopped);
|
||||
}
|
||||
|
||||
// And remove it
|
||||
using (ServiceInstaller si = new ServiceInstaller())
|
||||
{
|
||||
si.Context = new InstallContext($"old-{sc.ServiceName}-uninstall.log", null);
|
||||
si.ServiceName = sc.ServiceName;
|
||||
si.Uninstall(null);
|
||||
}
|
||||
}
|
||||
|
||||
using (var processInstaller = new ServiceProcessInstaller())
|
||||
using (var installer = new ServiceInstaller())
|
||||
{
|
||||
processInstaller.Account = ServiceAccount.LocalSystem;
|
||||
|
||||
installer.Context = new InstallContext("tgs-install.log", new string[] { String.Format(CultureInfo.InvariantCulture, "/assemblypath={0}", Assembly.GetEntryAssembly().Location) });
|
||||
installer.Description = "/tg/station 13 server running as a windows service";
|
||||
installer.DisplayName = "/tg/station server";
|
||||
installer.StartType = ServiceStartMode.Automatic;
|
||||
installer.ServicesDependedOn = new string[] { "Tcpip", "Dhcp", "Dnscache" };
|
||||
installer.ServiceName = ServerService.Name;
|
||||
installer.Parent = processInstaller;
|
||||
|
||||
var state = new ListDictionary();
|
||||
installer.Install(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Command line handler, always runs.
|
||||
/// </summary>
|
||||
@@ -112,82 +160,37 @@ namespace Tgstation.Server.Host.Service
|
||||
}
|
||||
}
|
||||
|
||||
using (var loggerFactory = new LoggerFactory())
|
||||
if (Install)
|
||||
{
|
||||
if (Install)
|
||||
{
|
||||
if (Uninstall)
|
||||
return; // oh no, it's retarded...
|
||||
if (Uninstall)
|
||||
return; // oh no, it's retarded...
|
||||
|
||||
// First check if the service already exists
|
||||
if (Environment.UserInteractive)
|
||||
foreach (ServiceController sc in ServiceController.GetServices())
|
||||
if (sc.ServiceName == "tgstation-server" || sc.ServiceName == "tgstation-server-4")
|
||||
{
|
||||
DialogResult result = MessageBox.Show($"You already have another TGS service installed ({sc.ServiceName}). Would you like to uninstall it now? Pressing \"No\" will cancel this install.", "TGS Service", MessageBoxButtons.YesNo);
|
||||
if (result != DialogResult.Yes)
|
||||
return; // is this needed after exit?
|
||||
|
||||
// Stop it first to give it some cleanup time
|
||||
if (sc.Status == ServiceControllerStatus.Running)
|
||||
{
|
||||
sc.Stop();
|
||||
sc.WaitForStatus(ServiceControllerStatus.Stopped);
|
||||
}
|
||||
|
||||
// And remove it
|
||||
using (ServiceInstaller si = new ServiceInstaller())
|
||||
{
|
||||
si.Context = new InstallContext($"old-{sc.ServiceName}-uninstall.log", null);
|
||||
si.ServiceName = sc.ServiceName;
|
||||
si.Uninstall(null);
|
||||
}
|
||||
}
|
||||
|
||||
using (var processInstaller = new ServiceProcessInstaller())
|
||||
using (var installer = new ServiceInstaller())
|
||||
{
|
||||
processInstaller.Account = ServiceAccount.LocalSystem;
|
||||
|
||||
installer.Context = new InstallContext("tgs-install.log", new string[] { String.Format(CultureInfo.InvariantCulture, "/assemblypath={0}", Assembly.GetEntryAssembly().Location) });
|
||||
installer.Description = "/tg/station 13 server running as a windows service";
|
||||
installer.DisplayName = "/tg/station server";
|
||||
installer.StartType = ServiceStartMode.Automatic;
|
||||
installer.ServicesDependedOn = new string[] { "Tcpip", "Dhcp", "Dnscache" };
|
||||
installer.ServiceName = ServerService.Name;
|
||||
installer.Parent = processInstaller;
|
||||
|
||||
var state = new ListDictionary();
|
||||
installer.Install(state);
|
||||
}
|
||||
|
||||
if (Configure)
|
||||
{
|
||||
Console.WriteLine("For this first run we'll launch the console runner so you may use the setup wizard.");
|
||||
Console.WriteLine("If it starts successfully, feel free to close it and then start the service from the Windows control panel.");
|
||||
}
|
||||
}
|
||||
else if (Uninstall)
|
||||
using (var installer = new ServiceInstaller())
|
||||
{
|
||||
installer.Context = new InstallContext("tgs-uninstall.log", null);
|
||||
installer.ServiceName = ServerService.Name;
|
||||
installer.Uninstall(null);
|
||||
}
|
||||
else if (!Configure)
|
||||
using (var service = new ServerService(WatchdogFactory, loggerFactory, Trace ? LogLevel.Trace : Debug ? LogLevel.Debug : LogLevel.Information))
|
||||
ServiceBase.Run(service);
|
||||
RunServiceInstall();
|
||||
|
||||
if (Configure)
|
||||
{
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
loggerFactory.AddConsole();
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
// DCT: None available
|
||||
await WatchdogFactory.CreateWatchdog(loggerFactory).RunAsync(true, Array.Empty<string>(), default);
|
||||
Console.WriteLine("For this first run we'll launch the console runner so you may use the setup wizard.");
|
||||
Console.WriteLine("If it starts successfully, feel free to close it and then start the service from the Windows control panel.");
|
||||
}
|
||||
}
|
||||
else if (Uninstall)
|
||||
using (var installer = new ServiceInstaller())
|
||||
{
|
||||
installer.Context = new InstallContext("tgs-uninstall.log", null);
|
||||
installer.ServiceName = ServerService.Name;
|
||||
installer.Uninstall(null);
|
||||
}
|
||||
else if (!Configure)
|
||||
{
|
||||
using (var service = new ServerService(WatchdogFactory, Trace ? LogLevel.Trace : Debug ? LogLevel.Debug : LogLevel.Information))
|
||||
ServiceBase.Run(service);
|
||||
}
|
||||
|
||||
if (Configure)
|
||||
{
|
||||
using (var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()))
|
||||
await WatchdogFactory.CreateWatchdog(loggerFactory).RunAsync(true, Array.Empty<string>(), default); // DCT: None available
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,20 @@ namespace Tgstation.Server.Host.Service
|
||||
/// <summary>
|
||||
/// The <see cref="IWatchdog"/> for the <see cref="ServerService"/>.
|
||||
/// </summary>
|
||||
readonly IWatchdog watchdog;
|
||||
readonly IWatchdogFactory watchdogFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Task"/> recieved from <see cref="IWatchdog.RunAsync(bool, string[], CancellationToken)"/> of <see cref="watchdog"/>.
|
||||
/// The minimum <see cref="Microsoft.Extensions.Logging.LogLevel"/> for the <see cref="EventLog"/>.
|
||||
/// </summary>
|
||||
readonly LogLevel minimumLogLevel;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILoggerFactory"/> used by the service.
|
||||
/// </summary>
|
||||
ILoggerFactory loggerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Task"/> that represents the running service.
|
||||
/// </summary>
|
||||
Task watchdogTask;
|
||||
|
||||
@@ -40,33 +50,19 @@ namespace Tgstation.Server.Host.Service
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ServerService"/> class.
|
||||
/// </summary>
|
||||
/// <param name="watchdogFactory">The <see cref="IWatchdogFactory"/> to create <see cref="watchdog"/> with.</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> for <paramref name="watchdogFactory"/>.</param>
|
||||
/// <param name="minumumLogLevel">The minimum <see cref="Microsoft.Extensions.Logging.LogLevel"/> to record in the event log.</param>
|
||||
public ServerService(IWatchdogFactory watchdogFactory, ILoggerFactory loggerFactory, LogLevel minumumLogLevel)
|
||||
/// <param name="watchdogFactory">The value of <see cref="watchdogFactory"/>.</param>
|
||||
/// <param name="minimumLogLevel">The minimum <see cref="Microsoft.Extensions.Logging.LogLevel"/> to record in the event log.</param>
|
||||
public ServerService(IWatchdogFactory watchdogFactory, LogLevel minimumLogLevel)
|
||||
{
|
||||
if (watchdogFactory == null)
|
||||
throw new ArgumentNullException(nameof(watchdogFactory));
|
||||
if (loggerFactory == null)
|
||||
throw new ArgumentNullException(nameof(loggerFactory));
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
loggerFactory.AddEventLog(new EventLogSettings
|
||||
{
|
||||
LogName = EventLog.Log,
|
||||
MachineName = EventLog.MachineName,
|
||||
SourceName = EventLog.Source,
|
||||
Filter = (message, logLevel) => logLevel >= minumumLogLevel,
|
||||
});
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
this.watchdogFactory = watchdogFactory ?? throw new ArgumentNullException(nameof(watchdogFactory));
|
||||
this.minimumLogLevel = minimumLogLevel;
|
||||
ServiceName = Name;
|
||||
watchdog = watchdogFactory.CreateWatchdog(loggerFactory);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
loggerFactory?.Dispose();
|
||||
cancellationTokenSource?.Dispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
@@ -74,9 +70,23 @@ namespace Tgstation.Server.Host.Service
|
||||
/// <inheritdoc />
|
||||
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,
|
||||
}));
|
||||
}
|
||||
|
||||
var watchdog = watchdogFactory.CreateWatchdog(loggerFactory);
|
||||
|
||||
cancellationTokenSource?.Dispose();
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
watchdogTask = RunWatchdog(args, cancellationTokenSource.Token);
|
||||
|
||||
watchdogTask = RunWatchdog(watchdog, args, cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -87,12 +97,13 @@ namespace Tgstation.Server.Host.Service
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the <see cref="watchdog"/>, stopping the service if it exits.
|
||||
/// Executes the <paramref name="watchdog"/>, stopping the service if it exits.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments for the <see cref="watchdog"/>.</param>
|
||||
/// <param name="watchdog">The <see cref="IWatchdog"/> to run.</param>
|
||||
/// <param name="args">The arguments for the <paramref name="watchdog"/>.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
async Task RunWatchdog(string[] args, CancellationToken cancellationToken)
|
||||
async Task RunWatchdog(IWatchdog watchdog, string[] args, CancellationToken cancellationToken)
|
||||
{
|
||||
await watchdog.RunAsync(false, args, cancellationTokenSource.Token);
|
||||
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="3.1.0" />
|
||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.0.2" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "6.0.8",
|
||||
"version": "6.0.15",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
|
||||
@@ -329,7 +329,7 @@ namespace Tgstation.Server.Host.Components.Chat
|
||||
if (channelIds == null)
|
||||
throw new ArgumentNullException(nameof(channelIds));
|
||||
|
||||
var task = SendMessage(message, channelIds, handlerCts.Token);
|
||||
var task = SendMessage(channelIds, null, message, handlerCts.Token);
|
||||
AddMessageTask(task);
|
||||
}
|
||||
|
||||
@@ -499,7 +499,7 @@ namespace Tgstation.Server.Host.Components.Chat
|
||||
.Select(x => x.Key)
|
||||
.ToList();
|
||||
|
||||
return SendMessage(message, wdChannels, cancellationToken);
|
||||
return SendMessage(wdChannels, null, message, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -641,11 +641,12 @@ namespace Tgstation.Server.Host.Components.Chat
|
||||
providerId,
|
||||
message.User.Channel.RealId);
|
||||
await SendMessage(
|
||||
"Processing error, check logs!",
|
||||
new List<ulong>
|
||||
{
|
||||
message.User.Channel.RealId,
|
||||
},
|
||||
null,
|
||||
"Processing error, check logs!",
|
||||
cancellationToken)
|
||||
;
|
||||
return;
|
||||
@@ -685,7 +686,7 @@ namespace Tgstation.Server.Host.Components.Chat
|
||||
if (splits.Count == 0)
|
||||
{
|
||||
// just a mention
|
||||
await SendMessage("Hi!", new List<ulong> { message.User.Channel.RealId }, cancellationToken);
|
||||
await SendMessage(new List<ulong> { message.User.Channel.RealId }, message, "Hi!", cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -731,7 +732,7 @@ namespace Tgstation.Server.Host.Components.Chat
|
||||
helpText = UnknownCommandMessage;
|
||||
}
|
||||
|
||||
await SendMessage(helpText, new List<ulong> { message.User.Channel.RealId }, cancellationToken);
|
||||
await SendMessage(new List<ulong> { message.User.Channel.RealId }, message, helpText, cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -739,19 +740,19 @@ namespace Tgstation.Server.Host.Components.Chat
|
||||
|
||||
if (commandHandler == default)
|
||||
{
|
||||
await SendMessage(UnknownCommandMessage, new List<ulong> { message.User.Channel.RealId }, cancellationToken);
|
||||
await SendMessage(new List<ulong> { message.User.Channel.RealId }, message, UnknownCommandMessage, cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
if (commandHandler.AdminOnly && !message.User.Channel.IsAdminChannel)
|
||||
{
|
||||
await SendMessage("Use this command in an admin channel!", new List<ulong> { message.User.Channel.RealId }, cancellationToken);
|
||||
await SendMessage(new List<ulong> { message.User.Channel.RealId }, message, "Use this command in an admin channel!", cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await commandHandler.Invoke(arguments, message.User, cancellationToken);
|
||||
if (result != null)
|
||||
await SendMessage(result, new List<ulong> { message.User.Channel.RealId }, cancellationToken);
|
||||
await SendMessage(new List<ulong> { message.User.Channel.RealId }, message, result, cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
@@ -763,8 +764,9 @@ namespace Tgstation.Server.Host.Components.Chat
|
||||
// error bc custom commands should reply about why it failed
|
||||
logger.LogError(e, "Error processing chat command");
|
||||
await SendMessage(
|
||||
"TGS: Internal error processing command! Check server logs!",
|
||||
new List<ulong> { message.User.Channel.RealId },
|
||||
message,
|
||||
"TGS: Internal error processing command! Check server logs!",
|
||||
cancellationToken)
|
||||
;
|
||||
}
|
||||
@@ -861,11 +863,12 @@ namespace Tgstation.Server.Host.Components.Chat
|
||||
/// <summary>
|
||||
/// Asynchronously send a given <paramref name="message"/> to a set of <paramref name="channelIds"/>.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to send.</param>
|
||||
/// <param name="channelIds">The <see cref="Models.ChatChannel.Id"/>s of the <see cref="Models.ChatChannel"/>s to send to.</param>
|
||||
/// <param name="replyTo">The <see cref="Message"/> to reply to.</param>
|
||||
/// <param name="message">The message to send.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
Task SendMessage(string message, IEnumerable<ulong> channelIds, CancellationToken cancellationToken)
|
||||
Task SendMessage(IEnumerable<ulong> channelIds, Message replyTo, string message, CancellationToken cancellationToken)
|
||||
{
|
||||
logger.LogTrace("Chat send \"{message}\" to channels: {channelIdsCommaSeperated}", message, String.Join(", ", channelIds));
|
||||
|
||||
@@ -880,7 +883,7 @@ namespace Tgstation.Server.Host.Components.Chat
|
||||
lock (providers)
|
||||
if (!providers.TryGetValue(channelMapping.ProviderId, out provider))
|
||||
return Task.CompletedTask;
|
||||
return provider.SendMessage(channelMapping.ProviderChannelId, message, cancellationToken);
|
||||
return provider.SendMessage(replyTo, message, channelMapping.ProviderChannelId, cancellationToken);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// Represents a message recieved by a <see cref="IProvider"/>.
|
||||
/// </summary>
|
||||
sealed class Message
|
||||
class Message
|
||||
{
|
||||
/// <summary>
|
||||
/// The text of the message.
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Remora.Discord.API.Abstractions.Objects;
|
||||
using Remora.Rest.Core;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="Message"/> containing the source <see cref="IMessageReference"/>.
|
||||
/// </summary>
|
||||
sealed class DiscordMessage : Message
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="IMessageReference"/> of the source <see cref="Message"/>.
|
||||
/// </summary>
|
||||
public Optional<IMessageReference> MessageReference { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -219,14 +219,21 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task SendMessage(ulong channelId, string message, CancellationToken cancellationToken)
|
||||
public override async Task SendMessage(Message replyTo, string message, ulong channelId, CancellationToken cancellationToken)
|
||||
{
|
||||
Optional<IMessageReference> replyToReference = default;
|
||||
if (replyTo != null && replyTo is DiscordMessage discordMessage)
|
||||
{
|
||||
replyToReference = discordMessage.MessageReference;
|
||||
}
|
||||
|
||||
var channelsClient = serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
|
||||
async Task SendToChannel(Snowflake channelId)
|
||||
{
|
||||
var result = await channelsClient.CreateMessageAsync(
|
||||
channelId,
|
||||
message,
|
||||
messageReference: replyToReference,
|
||||
ct: cancellationToken);
|
||||
|
||||
if (!result.IsSuccess)
|
||||
@@ -273,8 +280,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
Logger.LogTrace("Dispatching to {0} unmapped channels...", unmappedTextChannels.Count());
|
||||
await Task.WhenAll(
|
||||
unmappedTextChannels.Select(
|
||||
x => SendToChannel(x.ID)))
|
||||
;
|
||||
x => SendToChannel(x.ID)));
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -430,14 +436,25 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
|| messageCreateEvent.Author.ID == currentUserId)
|
||||
return Result.FromSuccess();
|
||||
|
||||
var messageReference = new MessageReference
|
||||
{
|
||||
ChannelID = messageCreateEvent.ChannelID,
|
||||
GuildID = messageCreateEvent.GuildID,
|
||||
MessageID = messageCreateEvent.ID,
|
||||
FailIfNotExists = false,
|
||||
};
|
||||
|
||||
if (basedMeme && messageCreateEvent.Content.Equals("Based on what?", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// DCT: None available
|
||||
await SendMessage(
|
||||
messageCreateEvent.ChannelID.Value,
|
||||
new DiscordMessage
|
||||
{
|
||||
MessageReference = messageReference,
|
||||
},
|
||||
"https://youtu.be/LrNu-SuFF_o",
|
||||
default)
|
||||
;
|
||||
messageCreateEvent.ChannelID.Value,
|
||||
default);
|
||||
return Result.FromSuccess();
|
||||
}
|
||||
|
||||
@@ -491,8 +508,9 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
messageCreateEvent.ID);
|
||||
}
|
||||
|
||||
var result = new Message
|
||||
var result = new DiscordMessage
|
||||
{
|
||||
MessageReference = messageReference,
|
||||
Content = content,
|
||||
User = new ChatUser
|
||||
{
|
||||
|
||||
@@ -63,11 +63,12 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
/// <summary>
|
||||
/// Send a message to the <see cref="IProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="channelId">The <see cref="ChannelRepresentation.RealId"/> to send to.</param>
|
||||
/// <param name="replyTo">The <see cref="Message"/> to reply to.</param>
|
||||
/// <param name="message">The message contents.</param>
|
||||
/// <param name="channelId">The <see cref="ChannelRepresentation.RealId"/> to send to.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
|
||||
Task SendMessage(ulong channelId, string message, CancellationToken cancellationToken);
|
||||
Task SendMessage(Message replyTo, string message, ulong channelId, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Set the interval at which the provider starts jobs to try to reconnect.
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task SendMessage(ulong channelId, string message, CancellationToken cancellationToken) => Task.Factory.StartNew(
|
||||
public override Task SendMessage(Message replyTo, string message, ulong channelId, CancellationToken cancellationToken) => Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
// IRC doesn't allow newlines
|
||||
@@ -230,7 +230,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
})));
|
||||
|
||||
await SendMessage(
|
||||
channelId,
|
||||
null,
|
||||
String.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"DM: Deploying revision: {0}{1}{2} BYOND Version: {3}{4}",
|
||||
@@ -243,11 +243,13 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
estimatedCompletionTime.HasValue
|
||||
? $" ETA: {estimatedCompletionTime - DateTimeOffset.UtcNow}"
|
||||
: String.Empty),
|
||||
channelId,
|
||||
cancellationToken);
|
||||
|
||||
return (errorMessage, dreamMakerOutput) => SendMessage(
|
||||
channelId,
|
||||
null,
|
||||
$"DM: Deployment {(errorMessage == null ? "complete" : "failed")}!",
|
||||
channelId,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract Task SendMessage(ulong channelId, string message, CancellationToken cancellationToken);
|
||||
public abstract Task SendMessage(Message replyTo, string message, ulong channelId, CancellationToken cancellationToken);
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract Task<Func<string, string, Task>> SendUpdateMessage(
|
||||
|
||||
@@ -6,6 +6,7 @@ using Elastic.CommonSchema.Serilog;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Serilog;
|
||||
using Serilog.Configuration;
|
||||
using Serilog.Sinks.Elasticsearch;
|
||||
@@ -82,10 +83,10 @@ namespace Tgstation.Server.Host.Extensions
|
||||
.WriteTo
|
||||
.Async(sinkConfiguration =>
|
||||
{
|
||||
sinkConfiguration.Console(
|
||||
outputTemplate: "[{Timestamp:HH:mm:ss}] {Level:w3}: {SourceContext:l} "
|
||||
var template = "[{Timestamp:HH:mm:ss}] {Level:w3}: {SourceContext:l} "
|
||||
+ SerilogContextTemplate
|
||||
+ "|IR:{InstanceReference}){NewLine} {Message:lj}{NewLine}{Exception}");
|
||||
+ "|IR:{InstanceReference}){NewLine} {Message:lj}{NewLine}{Exception}";
|
||||
sinkConfiguration.Console(outputTemplate: template, formatProvider: CultureInfo.InvariantCulture);
|
||||
sinkConfigurationAction?.Invoke(sinkConfiguration);
|
||||
});
|
||||
|
||||
|
||||
@@ -276,9 +276,12 @@ namespace Tgstation.Server.Host.Setup
|
||||
}
|
||||
|
||||
if (isSqliteDB && !dbExists)
|
||||
await Task.WhenAll(
|
||||
console.WriteAsync("Deleting test database file...", true, cancellationToken),
|
||||
ioManager.DeleteFile(databaseName, cancellationToken));
|
||||
{
|
||||
await console.WriteAsync("Deleting test database file...", true, cancellationToken);
|
||||
if (platformIdentifier.IsWindows)
|
||||
SqliteConnection.ClearAllPools();
|
||||
await ioManager.DeleteFile(databaseName, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -68,39 +68,39 @@
|
||||
<PackageReference Include="Elastic.CommonSchema.Serilog" Version="1.5.3" />
|
||||
<PackageReference Include="GitLabApiClient" Version="1.8.0" />
|
||||
<PackageReference Include="LibGit2Sharp" Version="0.27.0-preview-0034" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.9">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.15" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.15" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.15" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.15">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.15" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.15" />
|
||||
<!-- Required for https://github.com/coverlet-coverage/coverlet/issues/1381 -->
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />
|
||||
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
||||
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="2.2.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.7" />
|
||||
<PackageReference Include="Octokit" Version="3.0.0" />
|
||||
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.0.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.8" />
|
||||
<PackageReference Include="Octokit" Version="5.0.2" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.2" />
|
||||
<PackageReference Include="Remora.Discord" Version="2022.48.0" />
|
||||
<PackageReference Include="Remora.Discord" Version="2022.49.0" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="8.4.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="9.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.4.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.5.0" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
|
||||
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="6.0.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.23.1" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.27.0" />
|
||||
<PackageReference Include="System.Management" Version="6.0.0" />
|
||||
<PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="6.15.1" />
|
||||
<PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="6.20.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
+5
-5
@@ -8,14 +8,14 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
@@ -19,11 +19,9 @@ namespace Tgstation.Server.Host.Service.Tests
|
||||
[TestMethod]
|
||||
public void TestConstructionAndDisposal()
|
||||
{
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new ServerService(null, null, default));
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new ServerService(null, default));
|
||||
var mockWatchdogFactory = new Mock<IWatchdogFactory>();
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new ServerService(mockWatchdogFactory.Object, null, default));
|
||||
var mockLoggerFactory = new LoggerFactory();
|
||||
new ServerService(mockWatchdogFactory.Object, mockLoggerFactory, default).Dispose();
|
||||
new ServerService(mockWatchdogFactory.Object, default).Dispose();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -38,10 +36,9 @@ namespace Tgstation.Server.Host.Service.Tests
|
||||
CancellationToken cancellationToken;
|
||||
mockWatchdog.Setup(x => x.RunAsync(false, args, It.IsAny<CancellationToken>())).Callback((bool x, string[] _, CancellationToken token) => cancellationToken = token).Returns(Task.CompletedTask).Verifiable();
|
||||
var mockWatchdogFactory = new Mock<IWatchdogFactory>();
|
||||
var mockLoggerFactory = new LoggerFactory();
|
||||
mockWatchdogFactory.Setup(x => x.CreateWatchdog(mockLoggerFactory)).Returns(mockWatchdog.Object).Verifiable();
|
||||
mockWatchdogFactory.Setup(x => x.CreateWatchdog(It.IsNotNull<ILoggerFactory>())).Returns(mockWatchdog.Object).Verifiable();
|
||||
|
||||
using (var service = new ServerService(mockWatchdogFactory.Object, mockLoggerFactory, default))
|
||||
using (var service = new ServerService(mockWatchdogFactory.Object, default))
|
||||
{
|
||||
onStart.Invoke(service, new object[] { args });
|
||||
onStop.Invoke(service, Array.Empty<object>());
|
||||
|
||||
+5
-4
@@ -13,13 +13,14 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
+2
-2
@@ -9,8 +9,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
+5
-5
@@ -14,14 +14,14 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -152,7 +152,7 @@ namespace Tgstation.Server.Tests
|
||||
Assert.AreEqual(1, serverInformation.SwarmServers.Count);
|
||||
var controller = serverInformation.SwarmServers.SingleOrDefault(x => x.Identifier == "controller");
|
||||
Assert.IsNotNull(controller);
|
||||
Assert.AreEqual(controller.Address, "http://localhost:5011");
|
||||
Assert.AreEqual(controller.Address, new Uri("http://localhost:5011"));
|
||||
Assert.IsTrue(controller.Controller);
|
||||
}
|
||||
|
||||
@@ -270,17 +270,17 @@ namespace Tgstation.Server.Tests
|
||||
|
||||
var node1 = serverInformation.SwarmServers.SingleOrDefault(x => x.Identifier == "node1");
|
||||
Assert.IsNotNull(node1);
|
||||
Assert.AreEqual(node1.Address, "http://localhost:5012");
|
||||
Assert.AreEqual(node1.Address, new Uri("http://localhost:5012"));
|
||||
Assert.IsFalse(node1.Controller);
|
||||
|
||||
var node2 = serverInformation.SwarmServers.SingleOrDefault(x => x.Identifier == "node2");
|
||||
Assert.IsNotNull(node2);
|
||||
Assert.AreEqual(node2.Address, "http://localhost:5013");
|
||||
Assert.AreEqual(node2.Address, new Uri("http://localhost:5013"));
|
||||
Assert.IsFalse(node2.Controller);
|
||||
|
||||
var controller = serverInformation.SwarmServers.SingleOrDefault(x => x.Identifier == "controller");
|
||||
Assert.IsNotNull(controller);
|
||||
Assert.AreEqual(controller.Address, "http://localhost:5011");
|
||||
Assert.AreEqual(controller.Address, new Uri("http://localhost:5011"));
|
||||
Assert.IsTrue(controller.Controller);
|
||||
}
|
||||
|
||||
@@ -483,17 +483,17 @@ namespace Tgstation.Server.Tests
|
||||
|
||||
var node1 = serverInformation.SwarmServers.SingleOrDefault(x => x.Identifier == "node1");
|
||||
Assert.IsNotNull(node1);
|
||||
Assert.AreEqual(node1.Address, "http://localhost:5012");
|
||||
Assert.AreEqual(node1.Address, new Uri("http://localhost:5012"));
|
||||
Assert.IsFalse(node1.Controller);
|
||||
|
||||
var node2 = serverInformation.SwarmServers.SingleOrDefault(x => x.Identifier == "node2");
|
||||
Assert.IsNotNull(node2);
|
||||
Assert.AreEqual(node2.Address, "http://localhost:5013");
|
||||
Assert.AreEqual(node2.Address, new Uri("http://localhost:5013"));
|
||||
Assert.IsFalse(node2.Controller);
|
||||
|
||||
var controller = serverInformation.SwarmServers.SingleOrDefault(x => x.Identifier == "controller");
|
||||
Assert.IsNotNull(controller);
|
||||
Assert.AreEqual(controller.Address, "http://localhost:5011");
|
||||
Assert.AreEqual(controller.Address, new Uri("http://localhost:5011"));
|
||||
Assert.IsTrue(controller.Controller);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="../../build/Version.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
@@ -8,14 +8,14 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -75,7 +75,6 @@ namespace ReleaseNotes
|
||||
Task<Milestone> milestoneTask = null;
|
||||
var milestoneTaskLock = new object();
|
||||
var releaseDictionary = new Dictionary<string, List<Tuple<string, int, string>>>(StringComparer.OrdinalIgnoreCase);
|
||||
var authorizedUsers = new Dictionary<long, Task<bool>>();
|
||||
|
||||
bool postControlPanelMessage = false;
|
||||
|
||||
@@ -111,44 +110,13 @@ namespace ReleaseNotes
|
||||
// if (!fullPR.Merged)
|
||||
//return;
|
||||
|
||||
async Task BuildNotesFromComment(string comment, User user)
|
||||
void BuildNotesFromComment(string comment, User user)
|
||||
{
|
||||
if (comment == null)
|
||||
return;
|
||||
|
||||
async Task CommitNotes(string component, List<string> notes)
|
||||
void CommitNotes(string component, List<string> notes)
|
||||
{
|
||||
Task<bool> authTask;
|
||||
TaskCompletionSource<bool> ourTcs = null;
|
||||
lock (authorizedUsers)
|
||||
{
|
||||
if (!authorizedUsers.TryGetValue(user.Id, out authTask))
|
||||
{
|
||||
ourTcs = new TaskCompletionSource<bool>();
|
||||
authTask = ourTcs.Task;
|
||||
authorizedUsers.Add(user.Id, authTask);
|
||||
}
|
||||
}
|
||||
|
||||
if (ourTcs != null)
|
||||
try
|
||||
{
|
||||
//check if the user has access
|
||||
var perm = String.IsNullOrWhiteSpace(githubToken)
|
||||
? PermissionLevel.Write
|
||||
: (await client.Repository.Collaborator.ReviewPermission(RepoOwner, RepoName, user.Login).ConfigureAwait(false)).Permission;
|
||||
ourTcs.SetResult(perm == PermissionLevel.Write || perm == PermissionLevel.Admin);
|
||||
}
|
||||
catch
|
||||
{
|
||||
ourTcs.SetResult(false);
|
||||
throw;
|
||||
}
|
||||
|
||||
var authorized = await authTask.ConfigureAwait(false);
|
||||
if (!authorized)
|
||||
return;
|
||||
|
||||
lock (releaseDictionary)
|
||||
{
|
||||
foreach (var I in notes)
|
||||
@@ -180,7 +148,7 @@ namespace ReleaseNotes
|
||||
}
|
||||
if (trimmedLine.StartsWith("/:cl:", StringComparison.Ordinal))
|
||||
{
|
||||
await CommitNotes(targetComponent, notes);
|
||||
CommitNotes(targetComponent, notes);
|
||||
targetComponent = null;
|
||||
notes.Clear();
|
||||
continue;
|
||||
@@ -193,7 +161,9 @@ namespace ReleaseNotes
|
||||
}
|
||||
|
||||
var comments = await client.Issue.Comment.GetAllForIssue(RepoOwner, RepoName, fullPR.Number).ConfigureAwait(false);
|
||||
await Task.WhenAll(BuildNotesFromComment(fullPR.Body, fullPR.User), Task.WhenAll(comments.Select(x => BuildNotesFromComment(x.Body, x.User)))).ConfigureAwait(false);
|
||||
BuildNotesFromComment(fullPR.Body, fullPR.User);
|
||||
foreach(var x in comments)
|
||||
BuildNotesFromComment(x.Body, x.User);
|
||||
}
|
||||
|
||||
var tasks = new List<Task>();
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="octokit" Version="3.0.0" />
|
||||
<PackageReference Include="octokit" Version="5.0.2" />
|
||||
<PackageReference Include="Octokit.GraphQL" Version="0.2.0-beta" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user