Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/Nullinside.Api.Common/Twitch/ITwitchClientProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ public interface ITwitchClientProxy : IDisposable, IAsyncDisposable {
/// <summary>
/// Removes a callback for when the channel receives a new chat message.
/// </summary>
/// <param name="channel">The name of the channel to add the callback for.</param>
/// <param name="callback">The callback to remove.</param>
/// <returns>An asynchronous task.</returns>
void RemoveMessageCallback(Action<OnMessageReceivedArgs> callback);
void RemoveMessageCallback(string channel, Action<OnMessageReceivedArgs> callback);

/// <summary>
/// Adds a callback for when users are banned from the chat.
Expand All @@ -53,8 +54,9 @@ public interface ITwitchClientProxy : IDisposable, IAsyncDisposable {
/// <summary>
/// Removes a callback for when users are banned from the chat.
/// </summary>
/// <param name="channel">The name of the channel to add the callback for.</param>
/// <param name="callback">The callback to remove from when a user is banned.</param>
void RemoveBannedCallback(Action<OnUserBannedArgs> callback);
void RemoveBannedCallback(string channel, Action<OnUserBannedArgs> callback);

/// <summary>
/// Adds a callback for when the channel receives a raid.
Expand All @@ -67,7 +69,8 @@ public interface ITwitchClientProxy : IDisposable, IAsyncDisposable {
/// <summary>
/// Removes a callback for when the channel receives a raid.
/// </summary>
/// <param name="channel">The name of the channel to add the callback for.</param>
/// <param name="callback">The callback to remove.</param>
/// <returns>An asynchronous task.</returns>
void RemoveRaidCallback(Action<OnRaidNotificationArgs> callback);
void RemoveRaidCallback(string channel, Action<OnRaidNotificationArgs> callback);
}
102 changes: 67 additions & 35 deletions src/Nullinside.Api.Common/Twitch/TwitchClientProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ public class TwitchClientProxy : ITwitchClientProxy {
/// </summary>
private static TwitchClientProxy? instance;

/// <summary>
/// The callback(s) to invoke when a new instance is created.
/// </summary>
private static Action<TwitchClientProxy>? onInstanceCreated;

/// <summary>
/// The list of chats we attempted to join with the bot.
/// </summary>
Expand Down Expand Up @@ -61,17 +56,17 @@ public class TwitchClientProxy : ITwitchClientProxy {
/// <summary>
/// The callback(s) to invoke when a channel receives a chat message.
/// </summary>
private Action<OnMessageReceivedArgs>? onMessageReceived;
private Dictionary<string, Action<OnMessageReceivedArgs>?> _onMessageReceived = new();

/// <summary>
/// The callback(s) to invoke when a channel is raided.
/// </summary>
private Action<OnRaidNotificationArgs>? onRaid;
private Dictionary<string, Action<OnRaidNotificationArgs>?> onRaid = new();

/// <summary>
/// The callback(s) to invoke when a channel receives a ban message.
/// </summary>
private Action<OnUserBannedArgs>? onUserBanReceived;
private Dictionary<string, Action<OnUserBannedArgs>?> onUserBanReceived = new();

/// <summary>
/// The web socket to connect to twitch chat with.
Expand All @@ -98,7 +93,6 @@ public static TwitchClientProxy Instance {
get {
if (null == instance) {
instance = new TwitchClientProxy();
onInstanceCreated?.Invoke(instance);
}

return instance;
Expand Down Expand Up @@ -162,39 +156,60 @@ public async Task<bool> SendMessage(string channel, string message, uint retryCo
/// <inheritdoc />
public async Task AddMessageCallback(string channel, Action<OnMessageReceivedArgs> callback) {
await JoinChannel(channel);
onMessageReceived -= callback;
onMessageReceived += callback;
var channelSan = channel.ToLowerInvariant();
lock (_onMessageReceived) {
_onMessageReceived[channelSan] = callback;
}
}

/// <inheritdoc />
public void RemoveMessageCallback(Action<OnMessageReceivedArgs> callback) {
onMessageReceived -= callback;
public void RemoveMessageCallback(string channel, Action<OnMessageReceivedArgs> callback) {
bool shouldRemove = false;
var channelSan = channel.ToLowerInvariant();
lock (_onMessageReceived) {
_onMessageReceived.Remove(channel);
}

if (shouldRemove) {
client?.LeaveChannel(channelSan);

// First add the channel to the master list.
lock (joinedChannels) {
joinedChannels.Add(channelSan);
}
}
}

/// <inheritdoc />
public async Task AddBannedCallback(string channel, Action<OnUserBannedArgs> callback) {
await JoinChannel(channel);

onUserBanReceived -= callback;
onUserBanReceived += callback;
lock (onUserBanReceived) {
onUserBanReceived[channel] = callback;
}
}

/// <inheritdoc />
public void RemoveBannedCallback(Action<OnUserBannedArgs> callback) {
onUserBanReceived -= callback;
public void RemoveBannedCallback(string channel, Action<OnUserBannedArgs> callback) {
lock (onUserBanReceived) {
onUserBanReceived.Remove(channel);
}
}

/// <inheritdoc />
public async Task AddRaidCallback(string channel, Action<OnRaidNotificationArgs> callback) {
await JoinChannel(channel);

onRaid -= callback;
onRaid += callback;
lock (onRaid) {
onRaid[channel] = callback;
}
}

/// <inheritdoc />
public void RemoveRaidCallback(Action<OnRaidNotificationArgs> callback) {
onRaid -= callback;
public void RemoveRaidCallback(string channel, Action<OnRaidNotificationArgs> callback) {
lock (onRaid) {
onRaid.Remove(channel);
}
}

/// <inheritdoc />
Expand All @@ -203,17 +218,6 @@ public ValueTask DisposeAsync() {
return ValueTask.CompletedTask;
}

/// <inheritdoc />
public void AddInstanceCallback(Action<TwitchClientProxy> callback) {
onInstanceCreated -= callback;
onInstanceCreated += callback;
}

/// <inheritdoc />
public void RemoveInstanceCallback(Action<TwitchClientProxy> callback) {
onInstanceCreated -= callback;
}

/// <summary>
/// Joins a twitch channel.
/// </summary>
Expand Down Expand Up @@ -303,6 +307,10 @@ private async Task<bool> Connect() {
try {
bool isConnected = false;
lock (twitchClientLock) {
if (client?.IsConnected ?? false) {
return true;
}

// If this is a first time initialization, create a brand-new client.
bool haveNoClient = null == client;
if (haveNoClient) {
Expand Down Expand Up @@ -377,7 +385,13 @@ private async Task<bool> Connect() {
/// <param name="sender">The twitch client.</param>
/// <param name="e">The event arguments.</param>
private void TwitchChatClient_OnRaidNotification(object? sender, OnRaidNotificationArgs e) {
Delegate[]? invokeList = onRaid?.GetInvocationList();
Action<OnRaidNotificationArgs>? callback;
var channel = e.Channel.ToLowerInvariant();
lock (onRaid) {
onRaid.TryGetValue(channel, out callback);
}

Delegate[]? invokeList = callback?.GetInvocationList();
if (null == invokeList) {
return;
}
Expand All @@ -393,7 +407,19 @@ private void TwitchChatClient_OnRaidNotification(object? sender, OnRaidNotificat
/// <param name="sender">The twitch client.</param>
/// <param name="e">The event arguments.</param>
private void TwitchChatClient_OnMessageReceived(object? sender, OnMessageReceivedArgs e) {
Delegate[]? invokeList = onMessageReceived?.GetInvocationList();
Action<OnMessageReceivedArgs>? callbacks = null;
var channelSan = e.ChatMessage.Channel.ToLowerInvariant();
lock (_onMessageReceived) {
if (_onMessageReceived.TryGetValue(channelSan, out Action<OnMessageReceivedArgs>? messageReceivedCallback)) {
callbacks = messageReceivedCallback;
}
}

if (null == callbacks) {
return;
}

Delegate[]? invokeList = callbacks?.GetInvocationList();
if (null == invokeList) {
return;
}
Expand All @@ -409,7 +435,13 @@ private void TwitchChatClient_OnMessageReceived(object? sender, OnMessageReceive
/// <param name="sender">The twitch client.</param>
/// <param name="e">The event arguments.</param>
private void TwitchChatClient_OnUserBanned(object? sender, OnUserBannedArgs e) {
Delegate[]? invokeList = onUserBanReceived?.GetInvocationList();
Action<OnUserBannedArgs>? callback;
var channel = e.UserBan.Channel.ToLowerInvariant();
lock (onUserBanReceived) {
onUserBanReceived.TryGetValue(channel, out callback);
}

Delegate[]? invokeList = callback?.GetInvocationList();
if (null == invokeList) {
return;
}
Expand Down