Skip to content

Add GET voice-state REST wrappers#3265

Merged
Misha-133 merged 3 commits into
discord-net:devfrom
yury-opolev:feature/get-voice-state-rest
May 31, 2026
Merged

Add GET voice-state REST wrappers#3265
Misha-133 merged 3 commits into
discord-net:devfrom
yury-opolev:feature/get-voice-state-rest

Conversation

@yury-opolev

Copy link
Copy Markdown
Contributor

Wraps two voice-state GET endpoints that round out the PATCH pair already in DiscordRestApiClient:

  • GET /guilds/{guild.id}/voice-states/@me
  • GET /guilds/{guild.id}/voice-states/{user.id}

Both return null on 404 (the user is not currently in any voice channel of the guild).

Exposed as GetMyVoiceStateAsync and GetUserVoiceStateAsync on RestGuild and SocketGuild, returning a new RestVoiceState entity that mirrors the relevant fields from the REST response (channel id, mute/deaf/suppress/streaming/video flags, voice-session id, request-to-speak timestamp).

Why a new RestVoiceState rather than reusing IVoiceState

The REST response carries channel_id, not a full channel object. Implementing IVoiceState would require returning null for IVoiceChannel VoiceChannel even when the user is in voice (since null already means "not in voice" per the existing interface contract), which would be misleading. Exposing VoiceChannelId : ulong? directly avoids that ambiguity; callers who need the channel can resolve it via guild.GetVoiceChannelAsync(state.VoiceChannelId.Value).

Happy to revisit if maintainers prefer a different shape (e.g. implementing IVoiceState with a documented null contract, or pre-fetching the channel via an extra REST call inside GuildHelper).

Tests

Skipped — the change is REST glue and the 404→null mapping isn't reachable from the unit-test project's public surface. Live integration coverage exists in spirit via the existing RestGuildFixture flow but I did not add a test there to keep the patch self-contained. Happy to add tests if maintainers point at the right entry point.

Wraps GET /guilds/{guild.id}/voice-states/@me and
GET /guilds/{guild.id}/voice-states/{user.id}, symmetric with the
existing ModifyMyVoiceState / ModifyUserVoiceState PATCH wrappers.

Returns null on 404 (user not in any voice channel of the guild).

Exposed as GetMyVoiceStateAsync / GetUserVoiceStateAsync on RestGuild
and SocketGuild, returning a new RestVoiceState entity that carries
the user's voice channel id and state flags from the REST response.
@Misha-133 Misha-133 self-requested a review May 16, 2026 16:57
@Misha-133

Misha-133 commented May 31, 2026

Copy link
Copy Markdown
Member

I think we should still reuse the IVoiceState interface. While it is technically breaking the contract, it's a part of an outdated API model so imho it's fine. Also adding a separate VoiceChannelId property should help with it.
I will add the changes to the PR.

Also thanks for the contribution :))

@Misha-133 Misha-133 enabled auto-merge (squash) May 31, 2026 10:24
@Misha-133 Misha-133 merged commit 13d83da into discord-net:dev May 31, 2026
2 checks passed
internal SocketVoiceState(SocketVoiceChannel voiceChannel, DateTimeOffset? requestToSpeak, string sessionId, bool isSelfMuted, bool isSelfDeafened, bool isMuted, bool isDeafened, bool isSuppressed, bool isStream, bool isVideo)
{
VoiceChannel = voiceChannel;
VoiceChannelId = voiceChannel.Id;

@ROBdk97 ROBdk97 Jun 7, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
VoiceChannelId = voiceChannel.Id;
VoiceChannelId = voiceChannel?.Id;

Missing null check

This is causing a error for me if you join to/from no voice channel

Error handling Dispatch (VOICE_STATE_UPDATE)
System.TypeInitializationException: The type initializer for 'Discord.WebSocket.SocketVoiceState' threw an exception.
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at Discord.WebSocket.SocketVoiceState..ctor(SocketVoiceChannel voiceChannel, Nullable`1 requestToSpeak, String sessionId, Boolean isSelfMuted, Boolean isSelfDeafened, Boolean isMuted, Boolean isDeafened, Boolean isSuppressed, Boolean isStream, Boolean isVideo)
   at Discord.WebSocket.SocketVoiceState..cctor()
   --- End of inner exception stack trace ---
   at Discord.WebSocket.DiscordSocketClient.ProcessMessageAsync(GatewayOpCode opCode, Nullable`1 seq, String type, Object payload)
System.NullReferenceException: Object reference not set to an instance of an object.
   at Discord.WebSocket.SocketVoiceState..ctor(SocketVoiceChannel voiceChannel, Nullable`1 requestToSpeak, String sessionId, Boolean isSelfMuted, Boolean isSelfDeafened, Boolean isMuted, Boolean isDeafened, Boolean isSuppressed, Boolean isStream, Boolean isVideo)
   at Discord.WebSocket.SocketVoiceState..cctor()

I will create a Issue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants