From 2bd39b6895d01bf43b5d4ac5c873c1b9b541c8f0 Mon Sep 17 00:00:00 2001 From: houshmand-2005 Date: Wed, 24 Jul 2024 17:04:10 +0330 Subject: [PATCH] Add retry for all APIs --- telegram_bot/send_message.py | 15 +- utils/panel_api.py | 292 +++++++++++++++++++---------------- v2iplimit.py | 2 +- 3 files changed, 171 insertions(+), 138 deletions(-) diff --git a/telegram_bot/send_message.py b/telegram_bot/send_message.py index 7b9e580..5a58c35 100644 --- a/telegram_bot/send_message.py +++ b/telegram_bot/send_message.py @@ -9,13 +9,16 @@ async def send_logs(msg): """Send logs to all admins.""" admins = await check_admin() + retries = 2 if admins: for admin in admins: - try: - await application.bot.sendMessage( - chat_id=admin, text=msg, parse_mode="HTML" - ) - except Exception as e: # pylint: disable=broad-except - print(f"Failed to send message to admin {admin}: {e}") + for _ in range(retries): + try: + await application.bot.sendMessage( + chat_id=admin, text=msg, parse_mode="HTML" + ) + break + except Exception as e: # pylint: disable=broad-except + print(f"Failed to send message to admin {admin}: {e}") else: print("No admins found.") diff --git a/utils/panel_api.py b/utils/panel_api.py index b5e923f..1ea6db8 100644 --- a/utils/panel_api.py +++ b/utils/panel_api.py @@ -3,6 +3,7 @@ """ import asyncio +import random import sys from ssl import SSLError @@ -12,6 +13,7 @@ print("Module 'httpx' is not installed use: 'pip install httpx' to install it") sys.exit() from telegram_bot.send_message import send_logs + from utils.handel_dis_users import DISABLED_USERS, DisabledUsers from utils.logs import logger from utils.read_config import read_config @@ -36,7 +38,7 @@ async def get_token(panel_data: PanelType) -> PanelType | ValueError: "username": f"{panel_data.panel_username}", "password": f"{panel_data.panel_password}", } - for attempt in range(10): + for attempt in range(20): for scheme in ["https", "http"]: url = f"{scheme}://{panel_data.panel_domain}/api/admin/token" try: @@ -58,9 +60,9 @@ async def get_token(panel_data: PanelType) -> PanelType | ValueError: await send_logs(message) logger.error(message) continue - await asyncio.sleep(5 * attempt) + await asyncio.sleep(random.randint(2, 5) * attempt) message = ( - "Failed to get token after 10 attempts. Make sure the panel is running " + "Failed to get token after 20 attempts. Make sure the panel is running " + "and the username and password are correct." ) await send_logs(message) @@ -83,35 +85,39 @@ async def all_user(panel_data: PanelType) -> list[UserType] | ValueError: ValueError: If the function fails to get the users from both the HTTP and HTTPS endpoints. """ - get_panel_token = await get_token(panel_data) - if isinstance(get_panel_token, ValueError): - raise get_panel_token - token = get_panel_token.panel_token - headers = { - "Authorization": f"Bearer {token}", - } - for scheme in ["https", "http"]: - url = f"{scheme}://{panel_data.panel_domain}/api/users" - try: - async with httpx.AsyncClient(verify=False) as client: - response = await client.get(url, headers=headers, timeout=10) - response.raise_for_status() - user_inform = response.json() - return [UserType(name=user["username"]) for user in user_inform["users"]] - except SSLError: - continue - except httpx.HTTPStatusError: - message = f"[{response.status_code}] {response.text}" - await send_logs(message) - logger.error(message) - continue - except Exception as error: # pylint: disable=broad-except - message = f"An unexpected error occurred: {error}" - await send_logs(message) - logger.error(message) - continue + for attempt in range(20): + get_panel_token = await get_token(panel_data) + if isinstance(get_panel_token, ValueError): + raise get_panel_token + token = get_panel_token.panel_token + headers = { + "Authorization": f"Bearer {token}", + } + for scheme in ["https", "http"]: + url = f"{scheme}://{panel_data.panel_domain}/api/users" + try: + async with httpx.AsyncClient(verify=False) as client: + response = await client.get(url, headers=headers, timeout=10) + response.raise_for_status() + user_inform = response.json() + return [ + UserType(name=user["username"]) for user in user_inform["users"] + ] + except SSLError: + continue + except httpx.HTTPStatusError: + message = f"[{response.status_code}] {response.text}" + await send_logs(message) + logger.error(message) + continue + except Exception as error: # pylint: disable=broad-except + message = f"An unexpected error occurred: {error}" + await send_logs(message) + logger.error(message) + continue + await asyncio.sleep(random.randint(2, 5) * attempt) message = ( - "Failed to get users. make sure the panel is running " + "Failed to get users after 20 attempts. make sure the panel is running " + "and the username and password are correct." ) await send_logs(message) @@ -150,7 +156,9 @@ async def enable_all_user(panel_data: PanelType) -> None | ValueError: status = {"status": "active"} try: async with httpx.AsyncClient(verify=False) as client: - response = await client.put(url, json=status, headers=headers) + response = await client.put( + url, json=status, headers=headers, timeout=5 + ) response.raise_for_status() message = f"Enabled user: {username.name}" await send_logs(message) @@ -188,37 +196,53 @@ async def enable_selected_users( ValueError: If the function fails to enable the users on both the HTTP and HTTPS endpoints. """ - get_panel_token = await get_token(panel_data) - if isinstance(get_panel_token, ValueError): - raise get_panel_token - token = get_panel_token.panel_token - headers = { - "Authorization": f"Bearer {token}", - } for username in inactive_users: - for scheme in ["https", "http"]: - url = f"{scheme}://{panel_data.panel_domain}/api/user/{username}" + success = False + for attempt in range(5): + get_panel_token = await get_token(panel_data) + if isinstance(get_panel_token, ValueError): + raise get_panel_token + token = get_panel_token.panel_token + headers = { + "Authorization": f"Bearer {token}", + } status = {"status": "active"} - try: - async with httpx.AsyncClient(verify=False) as client: - response = await client.put(url, json=status, headers=headers) - response.raise_for_status() - message = f"Enabled user: {username}" - await send_logs(message) - logger.info(message) + for scheme in ["https", "http"]: + url = f"{scheme}://{panel_data.panel_domain}/api/user/{username}" + try: + async with httpx.AsyncClient(verify=False) as client: + response = await client.put( + url, json=status, headers=headers, timeout=5 + ) + response.raise_for_status() + message = f"Enabled user: {username}" + await send_logs(message) + logger.info(message) + success = True + break + except SSLError: + continue + except httpx.HTTPStatusError: + message = f"[{response.status_code}] {response.text}" + await send_logs(message) + logger.error(message) + continue + except Exception as error: # pylint: disable=broad-except + message = f"An unexpected error occurred: {error}" + await send_logs(message) + logger.error(message) + continue + if success: break - except SSLError: - continue - except httpx.HTTPStatusError: - message = f"[{response.status_code}] {response.text}" - await send_logs(message) - logger.error(message) - continue - except Exception as error: # pylint: disable=broad-except - message = f"An unexpected error occurred: {error}" - await send_logs(message) - logger.error(message) - continue + await asyncio.sleep(random.randint(2, 5) * attempt) + if not success: + message = ( + f"Failed enable user: {username} after 20 attempts. Make sure the panel is running " + + "and the username and password are correct." + ) + await send_logs(message) + logger.error(message) + raise ValueError(message) logger.info("Enabled selected users") @@ -238,40 +262,44 @@ async def disable_user(panel_data: PanelType, username: UserType) -> None | Valu ValueError: If the function fails to disable the user on both the HTTP and HTTPS endpoints. """ - get_panel_token = await get_token(panel_data) - if isinstance(get_panel_token, ValueError): - raise get_panel_token - token = get_panel_token.panel_token - headers = { - "Authorization": f"Bearer {token}", - } - status = {"status": "disabled"} - for scheme in ["https", "http"]: - url = f"{scheme}://{panel_data.panel_domain}/api/user/{username.name}" - try: - async with httpx.AsyncClient(verify=False) as client: - response = await client.put(url, json=status, headers=headers) - response.raise_for_status() - message = f"Disabled user: {username.name}" - await send_logs(message) - logger.info(message) - dis_obj = DisabledUsers() - await dis_obj.add_user(username.name) - return None - except SSLError: - continue - except httpx.HTTPStatusError: - message = f"[{response.status_code}] {response.text}" - await send_logs(message) - logger.error(message) - continue - except Exception as error: # pylint: disable=broad-except - message = f"An unexpected error occurred: {error}" - await send_logs(message) - logger.error(message) - continue + for attempt in range(20): + get_panel_token = await get_token(panel_data) + if isinstance(get_panel_token, ValueError): + raise get_panel_token + token = get_panel_token.panel_token + headers = { + "Authorization": f"Bearer {token}", + } + status = {"status": "disabled"} + for scheme in ["https", "http"]: + url = f"{scheme}://{panel_data.panel_domain}/api/user/{username.name}" + try: + async with httpx.AsyncClient(verify=False) as client: + response = await client.put( + url, json=status, headers=headers, timeout=5 + ) + response.raise_for_status() + message = f"Disabled user: {username.name}" + await send_logs(message) + logger.info(message) + dis_obj = DisabledUsers() + await dis_obj.add_user(username.name) + return None + except SSLError: + continue + except httpx.HTTPStatusError: + message = f"[{response.status_code}] {response.text}" + await send_logs(message) + logger.error(message) + continue + except Exception as error: # pylint: disable=broad-except + message = f"An unexpected error occurred: {error}" + await send_logs(message) + logger.error(message) + continue + await asyncio.sleep(random.randint(2, 5) * attempt) message = ( - f"Failed to disable user: {username.name}. Make sure the panel is running " + f"Failed disable user: {username.name} after 20 attempts. Make sure the panel is running " + "and the username and password are correct." ) await send_logs(message) @@ -294,46 +322,48 @@ async def get_nodes(panel_data: PanelType) -> list[NodeType] | ValueError: ValueError: If the function fails to get the nodes from both the HTTP and HTTPS endpoints. """ - get_panel_token = await get_token(panel_data) - if isinstance(get_panel_token, ValueError): - raise get_panel_token - token = get_panel_token.panel_token - headers = { - "Authorization": f"Bearer {token}", - } - all_nodes = [] - for scheme in ["https", "http"]: - url = f"{scheme}://{panel_data.panel_domain}/api/nodes" - try: - async with httpx.AsyncClient(verify=False) as client: - response = await client.get(url, headers=headers, timeout=10) - response.raise_for_status() - user_inform = response.json() - for node in user_inform: - all_nodes.append( - NodeType( - node_id=node["id"], - node_name=node["name"], - node_ip=node["address"], - status=node["status"], - message=node["message"], + for attempt in range(20): + get_panel_token = await get_token(panel_data) + if isinstance(get_panel_token, ValueError): + raise get_panel_token + token = get_panel_token.panel_token + headers = { + "Authorization": f"Bearer {token}", + } + all_nodes = [] + for scheme in ["https", "http"]: + url = f"{scheme}://{panel_data.panel_domain}/api/nodes" + try: + async with httpx.AsyncClient(verify=False) as client: + response = await client.get(url, headers=headers, timeout=10) + response.raise_for_status() + user_inform = response.json() + for node in user_inform: + all_nodes.append( + NodeType( + node_id=node["id"], + node_name=node["name"], + node_ip=node["address"], + status=node["status"], + message=node["message"], + ) ) - ) - return all_nodes - except SSLError: - continue - except httpx.HTTPStatusError: - message = f"[{response.status_code}] {response.text}" - await send_logs(message) - logger.error(message) - continue - except Exception as error: # pylint: disable=broad-except - message = f"An unexpected error occurred: {error}" - await send_logs(message) - logger.error(message) - continue + return all_nodes + except SSLError: + continue + except httpx.HTTPStatusError: + message = f"[{response.status_code}] {response.text}" + await send_logs(message) + logger.error(message) + continue + except Exception as error: # pylint: disable=broad-except + message = f"An unexpected error occurred: {error}" + await send_logs(message) + logger.error(message) + continue + await asyncio.sleep(random.randint(2, 5) * attempt) message = ( - "Failed to get nodes. make sure the panel is running " + "Failed to get nodes after 20 attempts. make sure the panel is running " + "and the username and password are correct." ) await send_logs(message) diff --git a/v2iplimit.py b/v2iplimit.py index deafaaa..3e48be9 100644 --- a/v2iplimit.py +++ b/v2iplimit.py @@ -28,7 +28,7 @@ from utils.read_config import read_config from utils.types import PanelType -VERSION = "1.0.6" +VERSION = "1.0.6.1" parser = argparse.ArgumentParser(description="Help message") parser.add_argument("--version", action="version", version=VERSION)