Esempio n. 1
0
    async def _websocket_closed_handler(
        self,
        guild: discord.Guild,
        player: lavalink.Player,
        extra: Dict,
        deafen: bool,
        disconnect: bool,
    ) -> None:
        guild_id = guild.id
        node = player.node
        voice_ws: DiscordWebSocket = node.get_voice_ws(guild_id)
        code = extra.get("code")
        by_remote = extra.get("byRemote", "")
        reason = extra.get("reason", "").strip()
        if self._ws_resume[guild_id].is_set():
            ws_audio_log.debug(
                f"WS EVENT | Discarding WS Closed event for guild {guild_id} -> "
                f"Socket Closed {voice_ws.socket._closing or voice_ws.socket.closed}.  "
                f"Code: {code} -- Remote: {by_remote} -- {reason}")
            return
        self._ws_resume[guild_id].set()
        if player.channel:
            current_perms = player.channel.permissions_for(
                player.channel.guild.me)
            has_perm = current_perms.speak and current_perms.connect
        else:
            has_perm = False
        channel_id = player.channel.id
        if voice_ws.socket._closing or voice_ws.socket.closed or not voice_ws.open:
            if player._con_delay:
                delay = player._con_delay.delay()
            else:
                player._con_delay = ExponentialBackoff(base=1)
                delay = player._con_delay.delay()
            ws_audio_log.warning(
                "YOU CAN IGNORE THIS UNLESS IT'S CONSISTENTLY REPEATING FOR THE SAME GUILD - "
                f"Voice websocket closed for guild {guild_id} -> "
                f"Socket Closed {voice_ws.socket._closing or voice_ws.socket.closed}.  "
                f"Code: {code} -- Remote: {by_remote} -- {reason}")
            ws_audio_log.debug(
                f"Reconnecting to channel {channel_id} in guild: {guild_id} | {delay:.2f}s"
            )
            await asyncio.sleep(delay)
            while voice_ws.socket._closing or voice_ws.socket.closed or not voice_ws.open:
                voice_ws = node.get_voice_ws(guild_id)
                await asyncio.sleep(0.1)

            if has_perm and player.current and player.is_playing:
                player.store("resumes", player.fetch("resumes", 0) + 1)
                await player.connect(deafen=deafen)
                await player.resume(player.current, start=player.position)
                ws_audio_log.info(
                    "Voice websocket reconnected "
                    f"to channel {channel_id} in guild: {guild_id} | "
                    f"Reason: Error code {code} & Currently playing.")
            elif has_perm and player.paused and player.current:
                player.store("resumes", player.fetch("resumes", 0) + 1)
                await player.connect(deafen=deafen)
                await player.pause(pause=True)
                ws_audio_log.info(
                    "Voice websocket reconnected "
                    f"to channel {channel_id} in guild: {guild_id} | "
                    f"Reason: Error code {code} & Currently Paused.")
            elif has_perm and (not disconnect) and (not player.is_playing):
                player.store("resumes", player.fetch("resumes", 0) + 1)
                await player.connect(deafen=deafen)
                ws_audio_log.info(
                    "Voice websocket reconnected "
                    f"to channel {channel_id} in guild: {guild_id} | "
                    f"Reason: Error code {code} & Not playing, but auto disconnect disabled."
                )
                self._ll_guild_updates.discard(guild_id)
            elif not has_perm:
                self.bot.dispatch("red_audio_audio_disconnect", guild)
                ws_audio_log.info(
                    "Voice websocket disconnected "
                    f"from channel {channel_id} in guild: {guild_id} | "
                    f"Reason: Error code {code} & Missing permissions.")
                self._ll_guild_updates.discard(guild_id)
                player.store("autoplay_notified", False)
                await player.stop()
                await player.disconnect()
                await self.config.guild_from_id(
                    guild_id=guild_id).currently_auto_playing_in.set([])
            else:
                self.bot.dispatch("red_audio_audio_disconnect", guild)
                ws_audio_log.info(
                    "Voice websocket disconnected "
                    f"from channel {channel_id} in guild: {guild_id} | "
                    f"Reason: Error code {code} & Unknown.")
                self._ll_guild_updates.discard(guild_id)
                player.store("autoplay_notified", False)
                await player.stop()
                await player.disconnect()
                await self.config.guild_from_id(
                    guild_id=guild_id).currently_auto_playing_in.set([])
        elif code in (42069, ):
            player.store("resumes", player.fetch("resumes", 0) + 1)
            await player.connect(deafen=deafen)
            await player.resume(player.current, start=player.position)
            ws_audio_log.info(
                f"Player resumed in channel {channel_id} in guild: {guild_id} | "
                f"Reason: Error code {code} & {reason}.")
        elif code in (4015, 4014, 4009, 4006, 1006):
            if (code == 4006 and has_perm and player._last_resume
                    and player._last_resume + datetime.timedelta(seconds=5) >
                    datetime.datetime.now(tz=datetime.timezone.utc)):
                attempts = player.fetch("resume_attempts", 0)
                player.store("resume_attempts", attempts + 1)
                channel = self.bot.get_channel(player.channel.id)
                should_skip = not channel.members or all(
                    m.bot for m in channel.members)
                if should_skip:
                    ws_audio_log.info(
                        "Voice websocket reconnected skipped "
                        f"for channel {channel_id} in guild: {guild_id} | "
                        f"Reason: Error code {code} & "
                        "Player resumed too recently and no human members connected."
                    )
                    return

            if player._con_delay:
                delay = player._con_delay.delay()
            else:
                player._con_delay = ExponentialBackoff(base=1)
                delay = player._con_delay.delay()
            ws_audio_log.debug(
                f"Reconnecting to channel {channel_id} in guild: {guild_id} | {delay:.2f}s"
            )
            await asyncio.sleep(delay)
            if has_perm and player.current and player.is_playing:
                await player.connect(deafen=deafen)
                await player.resume(player.current, start=player.position)
                ws_audio_log.info(
                    "Voice websocket reconnected "
                    f"to channel {channel_id} in guild: {guild_id} | "
                    f"Reason: Error code {code} & Player is active.")
            elif has_perm and player.paused and player.current:
                player.store("resumes", player.fetch("resumes", 0) + 1)
                await player.connect(deafen=deafen)
                await player.pause(pause=True)
                ws_audio_log.info(
                    "Voice websocket reconnected "
                    f"to channel {channel_id} in guild: {guild_id} | "
                    f"Reason: Error code {code} & Player is paused.")
            elif has_perm and (not disconnect) and (not player.is_playing):
                player.store("resumes", player.fetch("resumes", 0) + 1)
                await player.connect(deafen=deafen)
                ws_audio_log.info(
                    "Voice websocket reconnected "
                    f"to channel {channel_id} in guild: {guild_id} | "
                    f"Reason: Error code {code} & Not playing.")
                self._ll_guild_updates.discard(guild_id)
            elif not has_perm:
                self.bot.dispatch("red_audio_audio_disconnect", guild)
                ws_audio_log.info(
                    "Voice websocket disconnected "
                    f"from channel {channel_id} in guild: {guild_id} | "
                    f"Reason: Error code {code} & Missing permissions.")
                self._ll_guild_updates.discard(guild_id)
                player.store("autoplay_notified", False)
                await player.stop()
                await player.disconnect()
                await self.config.guild_from_id(
                    guild_id=guild_id).currently_auto_playing_in.set([])
        else:
            ws_audio_log.info(
                "WS EVENT - IGNORED (Healthy Socket) | "
                f"Voice websocket closed event for guild {guild_id} -> "
                f"Code: {code} -- Remote: {by_remote} -- {reason}")
        self._ws_resume[guild_id].clear()
Esempio n. 2
0
    async def _websocket_closed_handler(
        self,
        guild: discord.Guild,
        player: lavalink.Player,
        extra: Dict,
        deafen: bool,
        disconnect: bool,
    ) -> None:
        guild_id = guild.id
        event_channel_id = extra.get("channelID")
        try:
            if not self._ws_resume[guild_id].is_set():
                await self._ws_resume[guild_id].wait()
            else:
                self._ws_resume[guild_id].clear()
            node = player.node
            voice_ws: DiscordWebSocket = node.get_voice_ws(guild_id)
            code = extra.get("code")
            by_remote = extra.get("byRemote", "")
            reason = extra.get("reason", "No Specified Reason").strip()
            channel_id = player.channel.id
            try:
                event_channel_id, to_handle_code = await self._ws_op_codes[
                    guild_id].get()
            except asyncio.QueueEmpty:
                log.debug("Empty queue - Resuming Processor - Early exit")
                return

            if code != to_handle_code:
                code = to_handle_code
                if player.channel.id != event_channel_id:
                    code = 4014
            if event_channel_id != channel_id:
                ws_audio_log.info(
                    "Received an op code for a channel that is no longer valid; %d "
                    "Reason: Error code %d & %s, %r",
                    event_channel_id,
                    code,
                    reason,
                    player,
                )
                self._ws_op_codes[guild_id]._init(
                    self._ws_op_codes[guild_id]._maxsize)
                return
            if player.channel:
                has_perm = self.can_join_and_speak(player.channel)
            else:
                has_perm = False
            if code in (
                    1000,
            ) and has_perm and player.current and player.is_playing:
                player.store("resumes", player.fetch("resumes", 0) + 1)
                await player.resume(player.current,
                                    start=player.position,
                                    replace=True)
                ws_audio_log.info(
                    "Player resumed | Reason: Error code %d & %s, %r", code,
                    reason, player)
                self._ws_op_codes[guild_id]._init(
                    self._ws_op_codes[guild_id]._maxsize)
                return

            if voice_ws.socket._closing or voice_ws.socket.closed or not voice_ws.open:
                if player._con_delay:
                    delay = player._con_delay.delay()
                else:
                    player._con_delay = ExponentialBackoff(base=1)
                    delay = player._con_delay.delay()
                ws_audio_log.warning(
                    "YOU CAN IGNORE THIS UNLESS IT'S CONSISTENTLY REPEATING FOR THE SAME GUILD - "
                    "Voice websocket closed for guild %d -> "
                    "Socket Closed %s.  "
                    "Code: %d -- Remote: %s -- %s, %r",
                    guild_id,
                    voice_ws.socket._closing or voice_ws.socket.closed,
                    code,
                    by_remote,
                    reason,
                    player,
                )
                ws_audio_log.debug(
                    "Reconnecting to channel %d in guild: %d | %.2fs",
                    channel_id,
                    guild_id,
                    delay,
                )
                await asyncio.sleep(delay)
                while voice_ws.socket._closing or voice_ws.socket.closed or not voice_ws.open:
                    voice_ws = node.get_voice_ws(guild_id)
                    await asyncio.sleep(0.1)

                if has_perm and player.current and player.is_playing:
                    player.store("resumes", player.fetch("resumes", 0) + 1)
                    await player.connect(deafen=deafen)
                    await player.resume(player.current,
                                        start=player.position,
                                        replace=True)
                    ws_audio_log.info(
                        "Voice websocket reconnected "
                        "Reason: Error code %d & Currently playing, %r",
                        code,
                        player,
                    )
                elif has_perm and player.paused and player.current:
                    player.store("resumes", player.fetch("resumes", 0) + 1)
                    await player.connect(deafen=deafen)
                    await player.resume(player.current,
                                        start=player.position,
                                        replace=True,
                                        pause=True)
                    ws_audio_log.info(
                        "Voice websocket reconnected "
                        "Reason: Error code %d & Currently Paused, %r",
                        code,
                        player,
                    )
                elif has_perm and (not disconnect) and (not player.is_playing):
                    player.store("resumes", player.fetch("resumes", 0) + 1)
                    await player.connect(deafen=deafen)
                    ws_audio_log.info(
                        "Voice websocket reconnected "
                        "Reason: Error code %d & Not playing, but auto disconnect disabled, %r",
                        code,
                        player,
                    )
                    self._ll_guild_updates.discard(guild_id)
                elif not has_perm:
                    self.bot.dispatch("red_audio_audio_disconnect", guild)
                    ws_audio_log.info(
                        "Voice websocket disconnected "
                        "Reason: Error code %d & Missing permissions, %r",
                        code,
                        player,
                    )
                    self._ll_guild_updates.discard(guild_id)
                    player.store("autoplay_notified", False)
                    await player.stop()
                    await player.disconnect()
                    await self.config.guild_from_id(
                        guild_id=guild_id).currently_auto_playing_in.set([])
                else:
                    self.bot.dispatch("red_audio_audio_disconnect", guild)
                    ws_audio_log.info(
                        "Voice websocket disconnected Reason: Error code %d & Unknown, %r",
                        code,
                        player,
                    )
                    self._ll_guild_updates.discard(guild_id)
                    player.store("autoplay_notified", False)
                    await player.stop()
                    await player.disconnect()
                    await self.config.guild_from_id(
                        guild_id=guild_id).currently_auto_playing_in.set([])
            elif code in (
                    42069,
            ) and has_perm and player.current and player.is_playing:
                player.store("resumes", player.fetch("resumes", 0) + 1)
                await player.connect(deafen=deafen)
                await player.resume(player.current,
                                    start=player.position,
                                    replace=True)
                ws_audio_log.info(
                    "Player resumed - Reason: Error code %d & %s, %r", code,
                    reason, player)
            elif code in (4015, 4009, 4006, 4000, 1006):
                if player._con_delay:
                    delay = player._con_delay.delay()
                else:
                    player._con_delay = ExponentialBackoff(base=1)
                    delay = player._con_delay.delay()
                ws_audio_log.debug(
                    "Reconnecting to channel %d in guild: %d | %.2fs",
                    channel_id, guild_id, delay)
                await asyncio.sleep(delay)
                if has_perm and player.current and player.is_playing:
                    await player.connect(deafen=deafen)
                    await player.resume(player.current,
                                        start=player.position,
                                        replace=True)
                    ws_audio_log.info(
                        "Voice websocket reconnected "
                        "Reason: Error code %d & Player is active, %r",
                        code,
                        player,
                    )
                elif has_perm and player.paused and player.current:
                    player.store("resumes", player.fetch("resumes", 0) + 1)
                    await player.connect(deafen=deafen)
                    await player.resume(player.current,
                                        start=player.position,
                                        replace=True,
                                        pause=True)
                    ws_audio_log.info(
                        "Voice websocket reconnected "
                        "Reason: Error code %d & Player is paused, %r",
                        code,
                        player,
                    )
                elif has_perm and (not disconnect) and (not player.is_playing):
                    player.store("resumes", player.fetch("resumes", 0) + 1)
                    await player.connect(deafen=deafen)
                    ws_audio_log.info(
                        "Voice websocket reconnected "
                        "to channel %d in guild: %d | "
                        "Reason: Error code %d & Not playing, %r",
                        channel_id,
                        guild_id,
                        code,
                        player,
                    )
                    self._ll_guild_updates.discard(guild_id)
                elif not has_perm:
                    self.bot.dispatch("red_audio_audio_disconnect", guild)
                    ws_audio_log.info(
                        "Voice websocket disconnected "
                        "Reason: Error code %d & Missing permissions, %r",
                        code,
                        player,
                    )
                    self._ll_guild_updates.discard(guild_id)
                    player.store("autoplay_notified", False)
                    await player.stop()
                    await player.disconnect()
                    await self.config.guild_from_id(
                        guild_id=guild_id).currently_auto_playing_in.set([])
            else:
                if not player.paused and player.current:
                    player.store("resumes", player.fetch("resumes", 0) + 1)
                    await player.resume(player.current,
                                        start=player.position,
                                        replace=True)
                    ws_audio_log.info(
                        "WS EVENT - SIMPLE RESUME (Healthy Socket) | "
                        "Voice websocket closed event "
                        "Code: %d -- Remote: %s -- %s, %r",
                        code,
                        by_remote,
                        reason,
                        player,
                    )
                else:
                    ws_audio_log.info(
                        "WS EVENT - IGNORED (Healthy Socket) | "
                        "Voice websocket closed event "
                        "Code: %d -- Remote: %s -- %s, %r",
                        code,
                        by_remote,
                        reason,
                        player,
                    )
        except Exception:
            log.exception("Error in task")
        finally:
            self._ws_op_codes[guild_id]._init(
                self._ws_op_codes[guild_id]._maxsize)
            self._ws_resume[guild_id].set()