From 78056e00410153952d5a553fa47c213635e106bb Mon Sep 17 00:00:00 2001 From: Hampus Date: Sun, 30 Aug 2026 23:05:03 +0200 Subject: [PATCH] perf(gateway): pre-encode voice state update fanout (#2177) --- .../src/guild/voice/guild_voice_broadcast.erl | 16 ++++++- .../test/guild_voice_broadcast_tests.erl | 48 ++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/fluxer_gateway/src/guild/voice/guild_voice_broadcast.erl b/fluxer_gateway/src/guild/voice/guild_voice_broadcast.erl index 9b2ece042..e9998e73f 100644 --- a/fluxer_gateway/src/guild/voice/guild_voice_broadcast.erl +++ b/fluxer_gateway/src/guild/voice/guild_voice_broadcast.erl @@ -111,13 +111,27 @@ maybe_dispatch_voice_state_update(Pids, SanitizedVoiceState, State) -> gateway_dispatch_relay:dispatch_many( [Pid || Pid <- Pids, is_pid(Pid)], voice_state_update, - SanitizedVoiceState, + dispatch_payload(SanitizedVoiceState), GuildId ); undefined -> ok end. +-spec dispatch_payload(voice_state()) -> voice_state() | {pre_encoded, binary()}. +dispatch_payload(SanitizedVoiceState) -> + case voice_state_utils:voice_state_guild_id(SanitizedVoiceState) of + undefined -> + SanitizedVoiceState; + _GuildId -> + {pre_encoded, + iolist_to_binary( + json:encode( + guild_data_wire:payload(SanitizedVoiceState), fun json:encode_value/2 + ) + )} + end. + -spec state_guild_id(guild_state()) -> integer() | undefined. state_guild_id(State) -> case map_utils:get_integer(State, id, undefined) of diff --git a/fluxer_gateway/test/guild_voice_broadcast_tests.erl b/fluxer_gateway/test/guild_voice_broadcast_tests.erl index db399428a..e6b39205f 100644 --- a/fluxer_gateway/test/guild_voice_broadcast_tests.erl +++ b/fluxer_gateway/test/guild_voice_broadcast_tests.erl @@ -72,13 +72,22 @@ pump_relay_to_guild(GuildState) -> NewGuildState. collect_voice_state_dispatches() -> + [decoded_voice_state(Payload) || Payload <- collect_raw_voice_state_dispatches()]. + +collect_raw_voice_state_dispatches() -> receive {'$gen_cast', {dispatch, voice_state_update, Payload}} -> - [Payload | collect_voice_state_dispatches()] + [Payload | collect_raw_voice_state_dispatches()] after 0 -> [] end. +decoded_voice_state({pre_encoded, Bin}) -> json:decode(Bin); +decoded_voice_state(Payload) -> Payload. + +map_path_wire_bytes(VoiceState) -> + iolist_to_binary(json:encode(guild_data_wire:payload(VoiceState))). + confirm_join(ConnId, GuildState) -> VoiceServerState = (voice_server_state(GuildState))#{ pending_voice_connections => #{ConnId => pending_join(ConnId)} @@ -158,3 +167,40 @@ broadcast_sanitizes_routing_metadata_test() -> ?assertEqual( [broadcast_payload(join_voice_state(<<"conn1">>))], collect_voice_state_dispatches() ). + +guild_fanout_pre_encodes_identical_wire_bytes_test() -> + VS = join_voice_state(<<"conn1">>), + ?assertEqual( + {pre_encoded, map_path_wire_bytes(broadcast_payload(VS))}, dispatch_payload_for(VS) + ). + +guild_fanout_payload_never_touches_dm_voice_states_test() -> + {pre_encoded, Bin} = dispatch_payload_for(join_voice_state(<<"conn1">>)), + State = #{dm_voice_states => #{}}, + ?assertEqual( + State, + session_dispatch_guild:update_dm_voice_states_map( + voice_state_update, json:decode(Bin), State + ) + ). + +dm_scoped_voice_state_stays_a_map_and_updates_dm_voice_states_test() -> + DmVS = (join_voice_state(<<"conn1">>))#{<<"guild_id">> => null}, + Payload = dispatch_payload_for(DmVS), + ?assertEqual(broadcast_payload(DmVS), Payload), + State = session_dispatch_guild:update_dm_voice_states_map( + voice_state_update, Payload, #{dm_voice_states => #{}} + ), + ?assertEqual( + broadcast_payload(DmVS), + maps:get(<<"conn1">>, maps:get(dm_voice_states, State)) + ). + +dispatch_payload_for(VoiceState) -> + GuildState = base_guild_state(), + ok = guild_voice_broadcast:broadcast_voice_state_update( + VoiceState, voice_server_state(GuildState), null + ), + _ = pump_relay_to_guild(GuildState), + [Payload] = collect_raw_voice_state_dispatches(), + Payload.