Exemple #1
0
async def error_handler(update: types.Update, error: TelegramAPIError) -> None:
    for game in GAMES.values():
        asyncio.create_task(game.scan_for_stale_timer())
    if isinstance(error, MigrateToChat):
        if update.message.chat.id in GAMES:
            GAMES[error.migrate_to_chat_id] = GAMES.pop(update.message.chat.id)
            GAMES[error.migrate_to_chat_id].group_id = error.migrate_to_chat_id
        async with pool.acquire() as conn:
            await conn.execute(
                "UPDATE game SET group_id = $1 WHERE group_id = $2;\n"
                "UPDATE gameplayer SET group_id = $1 WHERE group_id = $2;\n"
                "DELETE FROM game WHERE group_id = $2;\n"
                "DELETE FROM gameplayer WHERE group_id = $2;",
                error.migrate_to_chat_id, update.message.chat.id)
        return
    await bot.send_message(
        ADMIN_GROUP_ID, f"`{error.__class__.__name__} @ "
        f"{update.message.chat.id if update.message and update.message.chat else 'idk'}`:\n"
        f"`{str(error)}`")
    if not update.message or not update.message.chat:
        return
    try:
        await update.message.reply(
            "Error occurred. My owner has been notified.")
    except TelegramAPIError:
        pass
    if update.message.chat.id in GAMES:
        GAMES[update.message.chat.id].state = GameState.KILLGAME
        await asyncio.sleep(2)
        try:
            del GAMES[update.message.chat.id]
            await update.message.reply("Game ended forcibly.")
        except:
            pass
Exemple #2
0
    async def main_loop(self, message: types.Message) -> None:
        # Attempt to fix issue of stuck game with negative timer.
        negative_timer = 0
        try:
            await self.send_message(
                f"A{'n' if self.name[0] in 'aeiou' else ''} {self.name} is starting.\n"
                f"{self.min_players}-{self.max_players} players are needed.\n"
                f"{self.time_left}s to /join.")
            await self.join(message)

            while True:
                await asyncio.sleep(1)
                if self.state == GameState.JOINING:
                    if self.time_left > 0:
                        self.time_left -= 1
                        if self.time_left in (15, 30, 60):
                            await self.send_message(
                                f"{self.time_left}s left to /join.")
                    else:
                        if len(self.players) < self.min_players:
                            await self.send_message(
                                "Not enough players. Game terminated.")
                            del GAMES[self.group_id]
                            return
                        else:
                            self.state = GameState.RUNNING
                            await self.send_message("Game is starting...")

                            random.shuffle(self.players)
                            self.players_in_game = self.players[:]

                            await self.running_initialization()
                            await self.send_turn_message()
                elif self.state == GameState.RUNNING:
                    # Check for prolonged negative timer
                    if self.time_left < 0:
                        negative_timer += 1
                    if negative_timer >= 5:
                        raise ValueError("Prolonged negative timer.")

                    if await self.running_phase_tick():  # True: Game ended
                        await self.update_db()
                        return
                elif self.state == GameState.KILLGAME:
                    await self.send_message("Game ended forcibly.")
                    del GAMES[self.group_id]
                    return
        except Exception as e:
            GAMES.pop(self.group_id, None)
            try:
                await self.send_message(
                    f"Game ended due to the following error:\n`{e.__class__.__name__}: {e}`.\n"
                    "My owner will be notified.")
            except:
                pass
            raise
Exemple #3
0
async def error_handler(update: types.Update, error: TelegramAPIError) -> None:
    for game in GAMES.values(
    ):  # TODO: Do this for group in which error occurs only
        asyncio.create_task(game.scan_for_stale_timer())

    if isinstance(error, MigrateToChat):
        if update.message.chat.id in GAMES:  # TODO: Test
            old_gid = GAMES[update.message.chat.id].group_id
            GAMES[error.migrate_to_chat_id] = GAMES.pop(update.message.chat.id)
            GAMES[error.migrate_to_chat_id].group_id = error.migrate_to_chat_id
            asyncio.create_task(
                send_admin_group(
                    f"Game moved from {old_gid} to {error.migrate_to_chat_id}."
                ))
        async with pool.acquire() as conn:
            await conn.execute(
                """\
                UPDATE game SET group_id = $1 WHERE group_id = $2;
                UPDATE gameplayer SET group_id = $1 WHERE group_id = $2;
                DELETE FROM game WHERE group_id = $2;
                DELETE FROM gameplayer WHERE group_id = $2;""",
                error.migrate_to_chat_id,
                update.message.chat.id,
            )
        await send_admin_group(f"Group migrated to {error.migrate_to_chat_id}."
                               )
        return

    send_admin_msg = await send_admin_group(
        f"`{error.__class__.__name__} @ "
        f"{update.message.chat.id if update.message and update.message.chat else 'idk'}`:\n"
        f"`{str(error)}`", )
    if not update.message or not update.message.chat:
        return

    try:
        await update.message.reply(
            "Error occurred. My owner has been notified.")
    except TelegramAPIError:
        pass

    if update.message.chat.id in GAMES:
        asyncio.create_task(
            send_admin_msg.reply(
                f"Killing game in {update.message.chat.id} consequently."))
        GAMES[update.message.chat.id].state = GameState.KILLGAME
        await asyncio.sleep(2)
        try:
            del GAMES[update.message.chat.id]
            await update.message.reply("Game ended forcibly.")
        except:
            pass
Exemple #4
0
    async def scan_for_stale_timer(self) -> None:
        # Check if game timer is stuck
        timer = self.time_left
        for _ in range(5):
            await asyncio.sleep(1)
            if timer != self.time_left and timer >= 0:
                return  # Timer not stuck

        await send_admin_group(
            f"Prolonged stale/negative timer detected in group `{self.group_id}`. Game Terminated."
        )
        try:
            await self.send_message(
                "Game timer is malfunctioning. Game terminated.")
        except:
            pass

        GAMES.pop(self.group_id, None)