mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-25 22:17:51 +01:00
Document ChatProviders
This commit is contained in:
@@ -4,7 +4,7 @@ using TGServiceInterface;
|
||||
namespace TGServerService.ChatProviders
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback for the chat provider recieving a message
|
||||
/// Callback for the chat provider recieving a <paramref name="message"/>
|
||||
/// </summary>
|
||||
/// <param name="ChatProvider">The chat provider the message came from</param>
|
||||
/// <param name="speaker">The username of the speaker</param>
|
||||
@@ -20,16 +20,16 @@ namespace TGServerService.ChatProviders
|
||||
interface ITGChatProvider : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets info for the provider
|
||||
/// Sets <paramref name="info"/> for the provider
|
||||
/// </summary>
|
||||
/// <param name="info">The info to set</param>
|
||||
/// <param name="info">The <see cref="ChatSetupInfo"/> to set</param>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
string SetProviderInfo(ChatSetupInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the info of the provider
|
||||
/// </summary>
|
||||
/// <returns>The info for the chat provider</returns>
|
||||
/// <returns>The <see cref="ChatSetupInfo"/> for the chat provider</returns>
|
||||
ChatSetupInfo ProviderInfo();
|
||||
|
||||
/// <summary>
|
||||
@@ -40,18 +40,18 @@ namespace TGServerService.ChatProviders
|
||||
/// <summary>
|
||||
/// Connects the chat provider if it's enabled
|
||||
/// </summary>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
/// <returns><see langword="null"/> on success, error message on failure</returns>
|
||||
string Connect();
|
||||
/// <summary>
|
||||
/// Forces a reconnection of the chat provider if it's enabled
|
||||
/// </summary>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
/// <returns><see langword="null"/> on success, error message on failure</returns>
|
||||
string Reconnect();
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the chat provider is connected
|
||||
/// </summary>
|
||||
/// <returns>true if the provider is connected, false otherwise</returns>
|
||||
/// <returns><see langword="true"/> if the provider is connected, <see langword="false"/> otherwise</returns>
|
||||
bool Connected();
|
||||
|
||||
/// <summary>
|
||||
@@ -60,18 +60,18 @@ namespace TGServerService.ChatProviders
|
||||
void Disconnect();
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to a channel
|
||||
/// Send a <paramref name="message"/> to a <paramref name="channel"/>
|
||||
/// </summary>
|
||||
/// <param name="message">The message to send</param>
|
||||
/// <param name="channel">The channel to send to</param>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
/// <returns><see langword="null"/> on success, error message on failure</returns>
|
||||
string SendMessageDirect(string message, string channel);
|
||||
|
||||
/// <summary>
|
||||
/// Broadcast a message to appropriate channels based on the message type
|
||||
/// Broadcast a <paramref name="message"/> to appropriate channels based on the message type
|
||||
/// </summary>
|
||||
/// <param name="msg">The message to send</param>
|
||||
/// <param name="mt">The message type</param>
|
||||
void SendMessage(string msg, MessageType mt);
|
||||
/// <param name="message">The message to send</param>
|
||||
/// <param name="mt">The <see cref="MessageType"/></param>
|
||||
void SendMessage(string message, MessageType mt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,25 +8,50 @@ using TGServiceInterface;
|
||||
|
||||
namespace TGServerService.ChatProviders
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ITGChatProvider"/> for Discord: https://discordapp.com/
|
||||
/// </summary>
|
||||
class DiscordChatProvider : ITGChatProvider
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public event OnChatMessage OnChatMessage;
|
||||
/// <summary>
|
||||
/// The Discord API client
|
||||
/// </summary>
|
||||
DiscordSocketClient client;
|
||||
/// <summary>
|
||||
/// The setup info for the provider
|
||||
/// </summary>
|
||||
DiscordSetupInfo DiscordConfig;
|
||||
/// <summary>
|
||||
/// Used for multithreading safety
|
||||
/// </summary>
|
||||
object DiscordLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// An <see cref="IDictionary{TKey, TValue}"/> of internal identifers => <see cref="ISocketMessageChannel"/>s we have seen
|
||||
/// </summary>
|
||||
IDictionary<ulong, ISocketMessageChannel> SeenPrivateChannels = new Dictionary<ulong, ISocketMessageChannel>();
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="DiscordChatProvider"/>
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="ChatSetupInfo"/></param>
|
||||
public DiscordChatProvider(ChatSetupInfo info)
|
||||
{
|
||||
Init(info);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public ChatSetupInfo ProviderInfo()
|
||||
{
|
||||
return DiscordConfig;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the Discord API <see cref="client"/> and <see cref="DiscordConfig"/>
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="ChatSetupInfo"/> to init <see cref="DiscordConfig"/> with</param>
|
||||
void Init(ChatSetupInfo info)
|
||||
{
|
||||
DiscordConfig = new DiscordSetupInfo(info);
|
||||
@@ -34,17 +59,27 @@ namespace TGServerService.ChatProviders
|
||||
client.MessageReceived += Client_MessageReceived;
|
||||
}
|
||||
|
||||
private bool CheckAdmin(SocketUser u)
|
||||
/// <summary>
|
||||
/// Checks if a <paramref name="user"/> is considered a chat admin
|
||||
/// </summary>
|
||||
/// <param name="user">The sender of a message</param>
|
||||
/// <returns><see langword="true"/> if <paramref name="user"/> is a chat admin, <see langword="false"/> otherwise</returns>
|
||||
private bool CheckAdmin(SocketUser user)
|
||||
{
|
||||
if (!DiscordConfig.AdminsAreSpecial)
|
||||
return DiscordConfig.AdminList.Contains(u.Id.ToString());
|
||||
if(u is SocketGuildUser sgu)
|
||||
return DiscordConfig.AdminList.Contains(user.Id.ToString());
|
||||
if(user is SocketGuildUser sgu)
|
||||
foreach (var I in sgu.Roles)
|
||||
if (DiscordConfig.AdminList.Contains(I.Id.ToString()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a channel the bot is in recieves a message or the bot is PM'd directly
|
||||
/// </summary>
|
||||
/// <param name="e">The event arguments</param>
|
||||
/// <returns>The task to run when this occurs</returns>
|
||||
private async Task Client_MessageReceived(SocketMessage e)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
@@ -81,6 +116,7 @@ namespace TGServerService.ChatProviders
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Connect()
|
||||
{
|
||||
try
|
||||
@@ -102,6 +138,7 @@ namespace TGServerService.ChatProviders
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Connected()
|
||||
{
|
||||
lock (DiscordLock)
|
||||
@@ -110,6 +147,7 @@ namespace TGServerService.ChatProviders
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Disconnect()
|
||||
{
|
||||
try
|
||||
@@ -126,12 +164,14 @@ namespace TGServerService.ChatProviders
|
||||
catch { }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Reconnect()
|
||||
{
|
||||
Disconnect();
|
||||
return Connect();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SendMessage(string msg, MessageType mt)
|
||||
{
|
||||
if (!Connected())
|
||||
@@ -158,6 +198,7 @@ namespace TGServerService.ChatProviders
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string SendMessageDirect(string message, string channelname)
|
||||
{
|
||||
if (!Connected())
|
||||
@@ -185,6 +226,10 @@ namespace TGServerService.ChatProviders
|
||||
return e.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shutsdown and disposes <see cref="client"/>
|
||||
/// </summary>
|
||||
void DisconnectAndDispose()
|
||||
{
|
||||
try
|
||||
@@ -198,6 +243,7 @@ namespace TGServerService.ChatProviders
|
||||
client.Dispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string SetProviderInfo(ChatSetupInfo info)
|
||||
{
|
||||
try
|
||||
@@ -228,8 +274,15 @@ namespace TGServerService.ChatProviders
|
||||
}
|
||||
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false; // To detect redundant calls
|
||||
/// <summary>
|
||||
/// To detect redundant <see cref="Dispose()"/> calls
|
||||
/// </summary>
|
||||
private bool disposedValue = false;
|
||||
|
||||
/// <summary>
|
||||
/// Implements the <see cref="IDisposable"/> pattern
|
||||
/// </summary>
|
||||
/// <param name="disposing"><see langword="true"/> if <see cref="Dispose()"/> was called manually, <see langword="false"/> if it was from the finalizer</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
@@ -252,8 +305,9 @@ namespace TGServerService.ChatProviders
|
||||
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
// Dispose(false);
|
||||
// }
|
||||
|
||||
// This code added to correctly implement the disposable pattern.
|
||||
/// <summary>
|
||||
/// Implements the <see cref="IDisposable"/> pattern
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
|
||||
@@ -4,25 +4,44 @@ using System.Threading;
|
||||
using TGServiceInterface;
|
||||
using Meebey.SmartIrc4net;
|
||||
|
||||
|
||||
namespace TGServerService.ChatProviders
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ITGChatProvider"/> for internet relay chat
|
||||
/// </summary>
|
||||
class IRCChatProvider : ITGChatProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Header used to mark that a channel is actually a query message
|
||||
/// </summary>
|
||||
const string PrivateMessageMarker = "---PRIVATE-MSG---";
|
||||
/// <summary>
|
||||
/// The irc client
|
||||
/// </summary>
|
||||
IrcFeatures irc;
|
||||
|
||||
/// <summary>
|
||||
/// Used for multithreading safety
|
||||
/// </summary>
|
||||
object IRCLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// The setup info for the provider
|
||||
/// </summary>
|
||||
IRCSetupInfo IRCConfig;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event OnChatMessage OnChatMessage;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public ChatSetupInfo ProviderInfo()
|
||||
{
|
||||
return IRCConfig;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="IRCChatProvider"/>
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="ChatSetupInfo"/></param>
|
||||
public IRCChatProvider(ChatSetupInfo info)
|
||||
{
|
||||
IRCConfig = new IRCSetupInfo(info);
|
||||
@@ -41,8 +60,8 @@ namespace TGServerService.ChatProviders
|
||||
irc.OnChannelMessage += Irc_OnChannelMessage;
|
||||
irc.OnQueryMessage += Irc_OnQueryMessage;
|
||||
}
|
||||
|
||||
//public api
|
||||
|
||||
/// <inheritdoc />
|
||||
public string SendMessageDirect(string message, string channel)
|
||||
{
|
||||
try
|
||||
@@ -64,6 +83,7 @@ namespace TGServerService.ChatProviders
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string SetProviderInfo(ChatSetupInfo info)
|
||||
{
|
||||
var convertedInfo = (IRCSetupInfo)info;
|
||||
@@ -84,6 +104,11 @@ namespace TGServerService.ChatProviders
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a message is considered sent from a chat admin
|
||||
/// </summary>
|
||||
/// <param name="e">The <see cref="IrcMessageData"/></param>
|
||||
/// <returns><see langword="true"/> if <paramref name="e"/> was sent by a chat admin, <see langword="false"/> otherwise</returns>
|
||||
private bool CheckAdmin(IrcMessageData e)
|
||||
{
|
||||
if (IRCConfig.AdminsAreSpecial)
|
||||
@@ -122,12 +147,21 @@ namespace TGServerService.ChatProviders
|
||||
return false;
|
||||
}
|
||||
|
||||
//private message
|
||||
/// <summary>
|
||||
/// Called when the bot recieves a query message
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of the event (usually <see cref="irc"/>)</param>
|
||||
/// <param name="e">The <see cref="IrcEventArgs"/></param>
|
||||
private void Irc_OnQueryMessage(object sender, IrcEventArgs e)
|
||||
{
|
||||
OnChatMessage(this, e.Data.Nick, e.Data.Nick + PrivateMessageMarker, e.Data.Message, CheckAdmin(e.Data), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a channel the bot is in recieves a message
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of the event (usually <see cref="irc"/>)</param>
|
||||
/// <param name="e">The <see cref="IrcEventArgs"/></param>
|
||||
private void Irc_OnChannelMessage(object sender, IrcEventArgs e)
|
||||
{
|
||||
var formattedMessage = e.Data.Message.Trim();
|
||||
@@ -144,7 +178,10 @@ namespace TGServerService.ChatProviders
|
||||
|
||||
OnChatMessage(this, e.Data.Nick, e.Data.Channel, formattedMessage, CheckAdmin(e.Data), IRCConfig.AdminChannels.Contains(e.Data.Channel.ToLower()));
|
||||
}
|
||||
//Joins configured channels
|
||||
|
||||
/// <summary>
|
||||
/// Joins all channels specified in <see cref="IRCConfig"/>
|
||||
/// </summary>
|
||||
void JoinChannels()
|
||||
{
|
||||
var hs = new HashSet<string>(); //for unique inserts
|
||||
@@ -165,7 +202,10 @@ namespace TGServerService.ChatProviders
|
||||
foreach (var I in hs)
|
||||
irc.RfcJoin(I);
|
||||
}
|
||||
//runs the login command
|
||||
|
||||
/// <summary>
|
||||
/// Sends a login query to <see cref="IRCSetupInfo.AuthTarget"/> with message <see cref="IRCSetupInfo.AuthMessage"/>
|
||||
/// </summary>
|
||||
void Login()
|
||||
{
|
||||
lock (IRCLock)
|
||||
@@ -174,7 +214,7 @@ namespace TGServerService.ChatProviders
|
||||
irc.SendMessage(SendType.Message, IRCConfig.AuthTarget, IRCConfig.AuthMessage);
|
||||
}
|
||||
}
|
||||
//public api
|
||||
/// <inheritdoc />
|
||||
public string Connect()
|
||||
{
|
||||
if (Connected() || !IRCConfig.Enabled)
|
||||
@@ -213,7 +253,9 @@ namespace TGServerService.ChatProviders
|
||||
}
|
||||
}
|
||||
|
||||
//This is the thread that listens for irc messages
|
||||
/// <summary>
|
||||
/// Runs the <see cref="irc"/> listener in a safe loop
|
||||
/// </summary>
|
||||
void IRCListen()
|
||||
{
|
||||
while (irc != null && Connected())
|
||||
@@ -224,14 +266,14 @@ namespace TGServerService.ChatProviders
|
||||
catch { }
|
||||
}
|
||||
|
||||
//public api
|
||||
/// <inheritdoc />
|
||||
public string Reconnect()
|
||||
{
|
||||
Disconnect();
|
||||
return Connect();
|
||||
}
|
||||
|
||||
//public api
|
||||
/// <inheritdoc />
|
||||
public void Disconnect()
|
||||
{
|
||||
try
|
||||
@@ -250,7 +292,7 @@ namespace TGServerService.ChatProviders
|
||||
Service.WriteError("IRC failed QnD: " + e.ToString(), EventID.ChatDisconnectFail);
|
||||
}
|
||||
}
|
||||
//public api
|
||||
/// <inheritdoc />
|
||||
public bool Connected()
|
||||
{
|
||||
lock (IRCLock)
|
||||
@@ -258,7 +300,7 @@ namespace TGServerService.ChatProviders
|
||||
return irc != null && irc.IsConnected;
|
||||
}
|
||||
}
|
||||
//public api
|
||||
/// <inheritdoc />
|
||||
public void SendMessage(string message, MessageType mt)
|
||||
{
|
||||
if (!Connected())
|
||||
@@ -279,8 +321,15 @@ namespace TGServerService.ChatProviders
|
||||
|
||||
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false; // To detect redundant calls
|
||||
/// <summary>
|
||||
/// To detect redundant <see cref="Dispose()"/> calls
|
||||
/// </summary>
|
||||
private bool disposedValue = false;
|
||||
|
||||
/// <summary>
|
||||
/// Implements the <see cref="IDisposable"/> pattern
|
||||
/// </summary>
|
||||
/// <param name="disposing"><see langword="true"/> if <see cref="Dispose()"/> was called manually, <see langword="false"/> if it was from the finalizer</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
@@ -306,6 +355,9 @@ namespace TGServerService.ChatProviders
|
||||
// }
|
||||
|
||||
// This code added to correctly implement the disposable pattern.
|
||||
/// <summary>
|
||||
/// Implements the <see cref="IDisposable"/> pattern
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
|
||||
Reference in New Issue
Block a user