[Feature] Voice channel status support (#2777)

* initial commit

* MOCKED CHANNELS AGRHHHHHHHH

* fix for sharded

* yup
This commit is contained in:
Mihail Gribkov
2023-11-18 23:42:14 +03:00
committed by GitHub
parent 8e4d449615
commit 8060dcf4ae
30 changed files with 323 additions and 17 deletions

View File

@@ -0,0 +1,15 @@
using Newtonsoft.Json;
namespace Discord.API.Gateway;
internal class VoiceChannelStatusUpdateEvent
{
[JsonProperty("id")]
public ulong Id { get; set; }
[JsonProperty("guild_id")]
public ulong GuildId { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
}

View File

@@ -76,6 +76,22 @@ namespace Discord.WebSocket
remove { _channelUpdatedEvent.Remove(value); }
}
internal readonly AsyncEvent<Func<SocketChannel, SocketChannel, Task>> _channelUpdatedEvent = new AsyncEvent<Func<SocketChannel, SocketChannel, Task>>();
/// <summary>
/// Fired when status of a voice channel is updated.
/// </summary>
/// <remarks>
/// The previous state of the channel is passed into the first parameter; the updated channel is passed into the second one.
/// </remarks>
public event Func<Cacheable<SocketVoiceChannel, ulong>, string, string, Task> VoiceChannelStatusUpdated
{
add { _voiceChannelStatusUpdated.Add(value); }
remove { _voiceChannelStatusUpdated.Remove(value); }
}
internal readonly AsyncEvent<Func<Cacheable<SocketVoiceChannel, ulong>, string, string, Task>> _voiceChannelStatusUpdated = new();
#endregion
#region Messages

View File

@@ -519,6 +519,8 @@ namespace Discord.WebSocket
client.WebhooksUpdated += (arg1, arg2) => _webhooksUpdated.InvokeAsync(arg1, arg2);
client.AuditLogCreated += (arg1, arg2) => _auditLogCreated.InvokeAsync(arg1, arg2);
client.VoiceChannelStatusUpdated += (arg1, arg2, arg3) => _voiceChannelStatusUpdated.InvokeAsync(arg1, arg2, arg3);
client.EntitlementCreated += (arg1) => _entitlementCreated.InvokeAsync(arg1);
client.EntitlementUpdated += (arg1, arg2) => _entitlementUpdated.InvokeAsync(arg1, arg2);
client.EntitlementDeleted += (arg1) => _entitlementDeleted.InvokeAsync(arg1);

View File

@@ -2333,6 +2333,24 @@ namespace Discord.WebSocket
}
break;
case "VOICE_CHANNEL_STATUS_UPDATE":
{
await _gatewayLogger.DebugAsync("Received Dispatch (VOICE_CHANNEL_STATUS_UPDATE)").ConfigureAwait(false);
var data = (payload as JToken).ToObject<VoiceChannelStatusUpdateEvent>(_serializer);
var guild = State.GetGuild(data.GuildId);
var channel = State.GetChannel(data.Id) as SocketVoiceChannel;
var channelCacheable = new Cacheable<SocketVoiceChannel, ulong>(channel, data.Id, channel is not null, () => null);
var before = (string)channel?.Status?.Clone();
var after = data.Status;
channel?.UpdateVoiceStatus(data.Status);
await TimedInvokeAsync(_voiceChannelStatusUpdated, nameof(VoiceChannelStatusUpdated), channelCacheable, before, after);
}
break;
#endregion
#region Invites

View File

@@ -0,0 +1,25 @@
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.WebSocket;
/// <summary>
/// Contains a piece of audit log data related to a voice channel status delete.
/// </summary>
public class SocketVoiceChannelStatusDeleteAuditLogData : ISocketAuditLogData
{
private SocketVoiceChannelStatusDeleteAuditLogData(ulong channelId)
{
ChannelId = channelId;
}
internal static SocketVoiceChannelStatusDeleteAuditLogData Create(DiscordSocketClient discord, EntryModel entry)
{
return new (entry.TargetId!.Value);
}
/// <summary>
/// Get the id of the channel status was removed in.
/// </summary>
public ulong ChannelId { get; }
}

View File

@@ -0,0 +1,31 @@
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.WebSocket;
/// <summary>
/// Contains a piece of audit log data related to a voice channel status update.
/// </summary>
public class SocketVoiceChannelStatusUpdatedAuditLogData : ISocketAuditLogData
{
private SocketVoiceChannelStatusUpdatedAuditLogData(string status, ulong channelId)
{
Status = status;
ChannelId = channelId;
}
internal static SocketVoiceChannelStatusUpdatedAuditLogData Create(DiscordSocketClient discord, EntryModel entry)
{
return new (entry.Options.Status, entry.TargetId!.Value);
}
/// <summary>
/// Gets the status that was set in the voice channel.
/// </summary>
public string Status { get; }
/// <summary>
/// Get the id of the channel status was updated in.
/// </summary>
public ulong ChannelId { get; }
}

View File

@@ -8,9 +8,9 @@ namespace Discord.WebSocket;
/// <summary>
/// Contains a piece of audit log data related to a webhook deletion.
/// </summary>
public class SocketWebhookDeleteAuditLogData : ISocketAuditLogData
public class SocketWebhookDeletedAuditLogData : ISocketAuditLogData
{
private SocketWebhookDeleteAuditLogData(ulong id, Model model)
private SocketWebhookDeletedAuditLogData(ulong id, Model model)
{
WebhookId = id;
ChannelId = model.ChannelId!.Value;
@@ -19,13 +19,13 @@ public class SocketWebhookDeleteAuditLogData : ISocketAuditLogData
Avatar = model.AvatarHash;
}
internal static SocketWebhookDeleteAuditLogData Create(DiscordSocketClient discord, EntryModel entry)
internal static SocketWebhookDeletedAuditLogData Create(DiscordSocketClient discord, EntryModel entry)
{
var changes = entry.Changes;
var (data, _) = AuditLogHelper.CreateAuditLogEntityInfo<Model>(changes, discord);
return new SocketWebhookDeleteAuditLogData(entry.TargetId!.Value,data);
return new SocketWebhookDeletedAuditLogData(entry.TargetId!.Value,data);
}
/// <summary>

View File

@@ -40,7 +40,7 @@ internal static class SocketAuditLogHelper
[ActionType.WebhookCreated] = SocketWebhookCreateAuditLogData.Create,
[ActionType.WebhookUpdated] = SocketWebhookUpdateAuditLogData.Create,
[ActionType.WebhookDeleted] = SocketWebhookDeleteAuditLogData.Create,
[ActionType.WebhookDeleted] = SocketWebhookDeletedAuditLogData.Create,
[ActionType.EmojiCreated] = SocketEmoteCreateAuditLogData.Create,
[ActionType.EmojiUpdated] = SocketEmoteUpdateAuditLogData.Create,
@@ -84,6 +84,10 @@ internal static class SocketAuditLogHelper
[ActionType.OnboardingQuestionCreated] = SocketOnboardingPromptCreatedAuditLogData.Create,
[ActionType.OnboardingQuestionUpdated] = SocketOnboardingPromptUpdatedAuditLogData.Create,
[ActionType.OnboardingUpdated] = SocketOnboardingUpdatedAuditLogData.Create,
[ActionType.VoiceChannelStatusUpdated] = SocketVoiceChannelStatusUpdatedAuditLogData.Create,
[ActionType.VoiceChannelStatusDeleted] = SocketVoiceChannelStatusDeleteAuditLogData.Create,
};
public static ISocketAuditLogData CreateData(DiscordSocketClient discord, EntryModel entry)

View File

@@ -43,6 +43,12 @@ namespace Discord.WebSocket
public IReadOnlyCollection<SocketGuildUser> Speakers
=> Users.Where(x => !x.IsSuppressed).ToImmutableArray();
/// <inheritdoc/>
/// <remarks>
/// This property is not supported in stage channels and will always return <see cref="string.Empty"/>.
/// </remarks>
public override string Status => string.Empty;
internal new SocketStageChannel Clone() => MemberwiseClone() as SocketStageChannel;
internal SocketStageChannel(DiscordSocketClient discord, ulong id, SocketGuild guild)
@@ -156,5 +162,13 @@ namespace Discord.WebSocket
return Discord.ApiClient.ModifyUserVoiceState(Guild.Id, user.Id, args);
}
/// <inheritdoc />
/// <remarks>
/// Setting voice channel status is not supported in stage channels.
/// </remarks>
/// <exception cref="NotSupportedException">Setting voice channel status is not supported in stage channels.</exception>
public override Task SetStatusAsync(string status, RequestOptions options = null)
=> throw new NotSupportedException("Setting voice channel status is not supported in stage channels.");
}
}

View File

@@ -38,6 +38,11 @@ namespace Discord.WebSocket
/// <inheritdoc/>
public VideoQualityMode VideoQualityMode { get; private set; }
/// <summary>
/// Gets the voice channel status set in this channel. <see langword="null" /> if it is not set.
/// </summary>
public virtual string Status { get; private set; }
/// <summary>
/// Gets a collection of users that are currently connected to this voice channel.
/// </summary>
@@ -51,12 +56,19 @@ namespace Discord.WebSocket
: base(discord, id, guild)
{
}
internal new static SocketVoiceChannel Create(SocketGuild guild, ClientState state, Model model)
{
var entity = new SocketVoiceChannel(guild?.Discord, model.Id, guild);
entity.Update(state, model);
return entity;
}
internal void UpdateVoiceStatus(string status)
{
Status = status;
}
/// <inheritdoc />
internal override void Update(ClientState state, Model model)
{
@@ -65,8 +77,13 @@ namespace Discord.WebSocket
UserLimit = model.UserLimit.GetValueOrDefault() != 0 ? model.UserLimit.Value : (int?)null;
VideoQualityMode = model.VideoQualityMode.GetValueOrDefault(VideoQualityMode.Auto);
RTCRegion = model.RTCRegion.GetValueOrDefault(null);
Status = model.Status.GetValueOrDefault(null);
}
/// <inheritdoc />
public virtual Task SetStatusAsync(string status, RequestOptions options = null)
=> ChannelHelper.ModifyVoiceChannelStatusAsync(this, status, Discord, options);
/// <inheritdoc />
public Task ModifyAsync(Action<VoiceChannelProperties> func, RequestOptions options = null)
=> ChannelHelper.ModifyAsync(this, Discord, func, options);