Get things building again

This commit is contained in:
Cyberboss
2018-07-16 15:52:12 -04:00
parent 88d6ff42fb
commit 9bbe7135f0
10 changed files with 121 additions and 24 deletions
+1 -2
View File
@@ -97,8 +97,7 @@
/datum/tgs_chat_channel
var/id //internal channel representation
var/friendly_name //user friendly channel name
var/server_name //server name the channel resides on
var/provider_name //chat provider for the channel
var/connection_name //the name of the configured chat connection
var/is_admin_channel //if the server operator has marked this channel for game admins only
var/is_private_channel //if this is a private chat channel
@@ -13,7 +13,7 @@
/// <summary>
/// The Discord channel ID
/// </summary>
public long DiscordChannelId { get; set; }
public long? DiscordChannelId { get; set; }
/// <summary>
/// If the <see cref="ChatChannel"/> is an admin channel
@@ -17,13 +17,18 @@
public string FriendlyName { get; set; }
/// <summary>
/// If this is considered a channel for admin commands
/// The name of the connection the <see cref="Channel"/> belongs to
/// </summary>
public bool IsAdminChannel { get; set; }
public string ConnectionName { get; set; }
/// <summary>
/// If this i
/// If this is considered a channel for admin commands
/// </summary>
public bool IsPrivateChannel { get; set; }
public bool IsAdmin { get; set; }
/// <summary>
/// If this is a 1-to-1 chat channel
/// </summary>
public bool IsPrivate { get; set; }
}
}
@@ -1,8 +1,6 @@
using Newtonsoft.Json;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models.Internal;
@@ -40,6 +38,9 @@ namespace Tgstation.Server.Host.Components.Chat
/// </summary>
readonly Dictionary<long, ChannelMapping> mappedChannels;
/// <summary>
/// The active <see cref="IJsonTrackingContext"/>s for the <see cref="Chat"/>
/// </summary>
readonly List<IJsonTrackingContext> trackingContexts;
/// <summary>
@@ -52,6 +53,11 @@ namespace Tgstation.Server.Host.Components.Chat
/// </summary>
long channelIdCounter;
/// <summary>
/// If <see cref="StartAsync(CancellationToken)"/> has been called
/// </summary>
bool started;
/// <summary>
/// Construct a <see cref="Chat"/>
/// </summary>
@@ -77,21 +83,43 @@ namespace Tgstation.Server.Host.Components.Chat
I.Value.Dispose();
}
/// <summary>
/// Remove a <see cref="IProvider"/> from <see cref="providers"/> and <see cref="mappedChannels"/> optionally updating the <see cref="trackingContexts"/> as well
/// </summary>
/// <param name="connectionId">The <see cref="ChatSettings.Id"/> of the <see cref="IProvider"/> to delete</param>
/// <param name="updateTrackings">If <see cref="trackingContexts"/> should be update</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in the <see cref="IProvider"/> being removed if it exists, <see langword="false"/> otherwise</returns>
async Task<IProvider> RemoveProvider(long connectionId, bool updateTrackings, CancellationToken cancellationToken)
{
IProvider provider;
lock (providers)
if (!providers.TryGetValue(connectionId, out provider))
return null;
Task task;
lock (mappedChannels)
{
foreach (var kvp in mappedChannels.Where(x => x.Value.ProviderId == connectionId))
mappedChannels.Remove(kvp.Key);
if (updateTrackings)
lock (trackingContexts)
task = Task.WhenAll(trackingContexts.Select(x => x.SetChannels(mappedChannels.Select(y => y.Value.Channel), cancellationToken)));
else
task = Task.CompletedTask;
}
await task.ConfigureAwait(false);
return provider;
}
/// <inheritdoc />
public async Task ChangeChannels(long connectionId, IEnumerable<Api.Models.ChatChannel> newChannels, CancellationToken cancellationToken)
{
if (newChannels == null)
throw new ArgumentNullException(nameof(newChannels));
IProvider provider;
lock (providers)
if (!providers.TryGetValue(connectionId, out provider))
return;
lock (mappedChannels)
foreach (var kvp in mappedChannels.Where(x => x.Value.ProviderId == connectionId))
{
mappedChannels.Remove(kvp.Key);
}
var provider = await RemoveProvider(connectionId, false, cancellationToken).ConfigureAwait(false);
if (provider == null)
return;
var results = await provider.MapChannels(newChannels, cancellationToken).ConfigureAwait(false);
if (results == null) //aborted
return;
@@ -152,7 +180,7 @@ namespace Tgstation.Server.Host.Components.Chat
lock (mappedChannels)
foreach (var channelId in mappedChannels.Where(x => x.Value.ProviderId == newSettings.Id).Select(x => x.Key))
mappedChannels.Remove(channelId);
if (newSettings.Enabled)
if (newSettings.Enabled && started)
await provider.Connect(cancellationToken).ConfigureAwait(false);
}
@@ -188,10 +216,14 @@ namespace Tgstation.Server.Host.Components.Chat
}
/// <inheritdoc />
public Task StartAsync(CancellationToken cancellationToken) => Task.WhenAll(providers.Select(x => x.Value).Select(x => x.Connect(cancellationToken)));
public async Task StartAsync(CancellationToken cancellationToken)
{
await Task.WhenAll(providers.Select(x => x.Value).Select(x => x.Connect(cancellationToken))).ConfigureAwait(false);
started = true;
}
/// <inheritdoc />
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StopAsync(CancellationToken cancellationToken) => Task.WhenAll(providers.Select(x => x.Value).Select(x => x.Disconnect(cancellationToken)));
/// <inheritdoc />
public async Task<IJsonTrackingContext> TrackJsons(string basePath, string channelsJsonName, string commandsJsonName, CancellationToken cancellationToken)
@@ -229,5 +261,8 @@ namespace Tgstation.Server.Host.Components.Chat
throw new InvalidOperationException("RegisterCommandHandler() already called!");
this.customCommandHandler = customCommandHandler ?? throw new ArgumentNullException(nameof(customCommandHandler));
}
/// <inheritdoc />
public Task DeleteConnection(long connectionId, CancellationToken cancellationToken) => RemoveProvider(connectionId, true, cancellationToken);
}
}
@@ -1,11 +1,29 @@
namespace Tgstation.Server.Host.Components.Chat.Commands
{
/// <summary>
/// Represents a command that can be invoked by talking to chat bots
/// </summary>
public abstract class Command
{
/// <summary>
/// The text to invoke the command. May not be "?" or "help" (case-insensitive)
/// </summary>
public string Name { get; set; }
/// <summary>
/// The help text to display when queires are made about the command
/// </summary>
public string HelpText { get; set; }
/// <summary>
/// If the command should only be available to <see cref="User"/>s who's <see cref="User.Channel"/> has <see cref="Channel.IsAdmin"/> set
/// </summary>
public bool AdminOnly { get; set; }
/// <summary>
/// Invoke the <see cref="Command"/>
/// </summary>
/// <param name="arguments">The text after <see cref="Name"/> with leading whitespace trimmed</param>
public abstract void Invoke(string arguments);
}
}
@@ -2,10 +2,20 @@
namespace Tgstation.Server.Host.Components.Chat.Commands
{
/// <summary>
/// Represents a command made from DM code
/// </summary>
public sealed class CustomCommand : Command
{
/// <summary>
/// The <see cref="ICustomCommandHandler"/> for the <see cref="CustomCommand"/>
/// </summary>
ICustomCommandHandler handler;
/// <summary>
/// Set a new <paramref name="handler"/>
/// </summary>
/// <param name="handler">The value of <see cref="handler"/></param>
public void SetHandler(ICustomCommandHandler handler)
{
if (this.handler != null)
@@ -33,6 +33,14 @@ namespace Tgstation.Server.Host.Components.Chat
/// <returns>A <see cref="Task"/> representing the running operation. Will complete immediately if the <see cref="ChatSettings.Enabled"/> property of <paramref name="newSettings"/> is <see langword="false"/></returns>
Task ChangeSettings(ChatSettings newSettings, CancellationToken cancellationToken);
/// <summary>
/// Disconnects and deletes a given connection
/// </summary>
/// <param name="connectionId">The <see cref="ChatSettings.Id"/> of the connection</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task DeleteConnection(long connectionId, CancellationToken cancellationToken);
/// <summary>
/// Change chat channels
/// </summary>
@@ -11,7 +11,19 @@ namespace Tgstation.Server.Host.Components.Chat
/// </summary>
public interface IJsonTrackingContext : IDisposable
{
/// <summary>
/// Read <see cref="CustomCommand"/>s from the <see cref="IJsonTrackingContext"/>
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in a <see cref="IReadOnlyList{T}"/> of <see cref="CustomCommand"/>s in the <see cref="IJsonTrackingContext"/></returns>
Task<IReadOnlyList<CustomCommand>> GetCustomCommands(CancellationToken cancellationToken);
/// <summary>
/// Writes information about connected <paramref name="channels"/> to the <see cref="IJsonTrackingContext"/>
/// </summary>
/// <param name="channels">The <see cref="Channel"/>s to write out</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task SetChannels(IEnumerable<Channel> channels, CancellationToken cancellationToken);
}
}
@@ -32,6 +32,13 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
/// <returns>A <see cref="Task{TResult}"/> resulting in <see langword="true"/> on success, <see langword="false"/> otherwise</returns>
Task<bool> Connect(CancellationToken cancellationToken);
/// <summary>
/// Gracefully disconnects the provider. Implies a call to <see cref="IDisposable.Dispose"/>
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task Disconnect(CancellationToken cancellationToken);
/// <summary>
/// Get the <see cref="Channel"/>s for given <paramref name="channels"/>
/// </summary>
@@ -1,10 +1,13 @@
namespace Tgstation.Server.Host.Components.Chat
{
/// <summary>
///
/// </summary>
public sealed class User
{
long Id { get; set; }
string FriendlyName { get; set; }
string Mention { get; set; }
Channel channel { get; set; }
Channel Channel { get; set; }
}
}