Adds chat broadcasting and update channels

This commit is contained in:
Jordan Brown
2018-08-08 14:39:17 -04:00
parent a9e4400802
commit 937bcbb6d2
5 changed files with 74 additions and 1 deletions
@@ -28,5 +28,11 @@ namespace Tgstation.Server.Api.Models
/// </summary>
[Required]
public bool? IsWatchdogChannel { get; set; }
/// <summary>
/// If the <see cref="ChatChannel"/> is an updates channel
/// </summary>
[Required]
public bool? IsUpdatesChannel { get; set; }
}
}
@@ -20,6 +20,11 @@
/// </summary>
public bool IsWatchdogChannel { get; set; }
/// <summary>
/// If the <see cref="Channel"/> is an updates channel
/// </summary>
public bool IsUpdatesChannel { get; set; }
/// <summary>
/// The <see cref="Components.Chat.Channel"/> with the mapped Id
/// </summary>
@@ -342,6 +342,7 @@ namespace Tgstation.Server.Host.Components.Chat
var mappings = Enumerable.Zip(newChannels, results, (x, y) => new ChannelMapping
{
IsWatchdogChannel = x.IsWatchdogChannel == true,
IsUpdatesChannel = x.IsUpdatesChannel == true,
ProviderChannelId = y.RealId,
ProviderId = connectionId,
Channel = y
@@ -456,11 +457,21 @@ namespace Tgstation.Server.Host.Components.Chat
public Task SendWatchdogMessage(string message, CancellationToken cancellationToken)
{
List<ulong> wdChannels;
message = String.Format(CultureInfo.InvariantCulture, "Watchdog: {0}", message);
lock (mappedChannels) //so it doesn't change while we're using it
wdChannels = mappedChannels.Where(x => x.Value.IsWatchdogChannel).Select(x => x.Key).ToList();
return SendMessage(message, wdChannels, cancellationToken);
}
/// <inheritdoc />
public Task SendUpdateMessage(string message, CancellationToken cancellationToken)
{
List<ulong> wdChannels;
lock (mappedChannels) //so it doesn't change while we're using it
wdChannels = mappedChannels.Where(x => x.Value.IsUpdatesChannel).Select(x => x.Key).ToList();
return SendMessage(message, wdChannels, cancellationToken);
}
/// <inheritdoc />
public async Task StartAsync(CancellationToken cancellationToken)
{
@@ -532,5 +543,14 @@ namespace Tgstation.Server.Host.Components.Chat
provider.Dispose();
}
}
/// <inheritdoc />
public Task SendBroadcast(string message, CancellationToken cancellationToken)
{
List<ulong> wdChannels;
lock (mappedChannels) //so it doesn't change while we're using it
wdChannels = mappedChannels.Select(x => x.Key).ToList();
return SendMessage(message, wdChannels, cancellationToken);
}
}
}
@@ -67,6 +67,22 @@ namespace Tgstation.Server.Host.Components.Chat
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task SendWatchdogMessage(string message, CancellationToken cancellationToken);
/// <summary>
/// Send a chat <paramref name="message"/> to configured update channels
/// </summary>
/// <param name="message">The message being sent</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task SendUpdateMessage(string message, CancellationToken cancellationToken);
/// <summary>
/// Send a chat to all channels
/// </summary>
/// <param name="message">The message being sent</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task SendBroadcast(string message, CancellationToken cancellationToken);
/// <summary>
/// Start tracking json files for commands and channels
/// </summary>
@@ -56,6 +56,16 @@ namespace Tgstation.Server.Host.Components
/// </summary>
readonly Dictionary<string, IInteropConsumer> interopConsumers;
/// <summary>
/// <see cref="List{T}"/> of <see cref="Task"/>s to finish in <see cref="StopAsync(CancellationToken)"/>
/// </summary>
readonly List<Task> shutdownTasks;
/// <summary>
/// Used as a temporary <see cref="CancellationTokenSource"/> for <see cref="shutdownTasks"/>
/// </summary>
readonly CancellationTokenSource shutdownCancellationTokenSource;
/// <summary>
/// Construct an <see cref="InstanceManager"/>
/// </summary>
@@ -65,17 +75,30 @@ namespace Tgstation.Server.Host.Components
/// <param name="application">The value of <see cref="application"/></param>
/// <param name="jobManager">The value of <see cref="jobManager"/></param>
/// <param name="logger">The value of <see cref="logger"/></param>
public InstanceManager(IInstanceFactory instanceFactory, IIOManager ioManager, IDatabaseContextFactory databaseContextFactory, IApplication application, IJobManager jobManager, ILogger<InstanceManager> logger)
public InstanceManager(IInstanceFactory instanceFactory, IIOManager ioManager, IDatabaseContextFactory databaseContextFactory, IApplication application, IJobManager jobManager, IServerControl serverControl, ILogger<InstanceManager> logger)
{
this.instanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
this.application = application ?? throw new ArgumentNullException(nameof(application));
this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
if (serverControl == null)
throw new ArgumentNullException(nameof(serverControl));
var cancellationToken = shutdownCancellationTokenSource.Token;
serverControl.RegisterForRestart(() =>
{
lock (this)
shutdownTasks.AddRange(instances.Select(x => x.Value.Chat.SendBroadcast("TGS: Restart requested...", cancellationToken)));
});
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
instances = new Dictionary<long, IInstance>();
interopConsumers = new Dictionary<string, IInteropConsumer>();
shutdownTasks = new List<Task>();
shutdownCancellationTokenSource = new CancellationTokenSource();
}
/// <inheritdoc />
@@ -83,6 +106,7 @@ namespace Tgstation.Server.Host.Components
{
foreach (var I in instances)
I.Value.Dispose();
shutdownCancellationTokenSource.Dispose();
}
/// <inheritdoc />
@@ -191,6 +215,8 @@ namespace Tgstation.Server.Host.Components
/// <inheritdoc />
public async Task StopAsync(CancellationToken cancellationToken)
{
using (cancellationToken.Register(() => shutdownCancellationTokenSource.Cancel()))
await Task.WhenAll(shutdownTasks).ConfigureAwait(false);
await Task.WhenAll(instances.Select(x => x.Value.StopAsync(cancellationToken))).ConfigureAwait(false);
await jobManager.StopAsync(cancellationToken).ConfigureAwait(false);
}