with init request

This commit is contained in:
2024-12-21 16:13:22 +03:00
parent b8bbb24dca
commit 4d81dce8ad
2 changed files with 18 additions and 248 deletions

View File

@ -1,245 +0,0 @@
import asyncio
import collections
import logging
import platform
import re
import time
import typing
from telethon import TelegramClient as TC
from telethon import __name__ as __base_name__
from telethon._updates import EntityCache as MbEntityCache
from telethon._updates import MessageBox
from telethon.extensions import markdown
from telethon.network import Connection, ConnectionTcpFull, MTProtoSender, TcpMTProxy
from telethon.sessions import MemorySession, Session, SQLiteSession
from telethon.tl import functions, types
DEFAULT_DC_ID = 2
DEFAULT_IPV4_IP = "149.154.167.51"
DEFAULT_IPV6_IP = "2001:67c:4e8:f002::a"
DEFAULT_PORT = 443
_base_log = logging.getLogger(__base_name__)
API_PACKS = {
4: "android",
5: "android",
6: "android",
8: "ios",
2834: "macos",
2040: "tdesktop",
17349: "tdesktop",
21724: "android",
16623: "android",
2496: "",
}
class TelegramClient(TC):
def __init__(
self: "TelegramClient",
session: "typing.Union[str, Session]",
api_id: int,
api_hash: str,
*,
connection: "typing.Type[Connection]" = ConnectionTcpFull,
use_ipv6: bool = False,
proxy: typing.Union[tuple, dict] = None, # type: ignore
local_addr: typing.Union[str, tuple] = None, # type: ignore
timeout: int = 10,
request_retries: int = 5,
connection_retries: int = 5,
retry_delay: int = 1,
auto_reconnect: bool = True,
sequential_updates: bool = False,
flood_sleep_threshold: int = 60,
raise_last_call_error: bool = False,
device_model: str = None, # type: ignore
system_version: str = None, # type: ignore
app_version: str = None, # type: ignore
lang_code: str = "en",
system_lang_code: str = "en",
base_logger: typing.Union[str, logging.Logger] = None, # type: ignore
receive_updates: bool = True,
catch_up: bool = False,
entity_cache_limit: int = 5000,
):
if not api_id or not api_hash:
raise ValueError(
"Your API ID or Hash cannot be empty or None. "
"Refer to telethon.rtfd.io for more information."
)
self._use_ipv6 = use_ipv6
if isinstance(base_logger, str):
base_logger = logging.getLogger(base_logger)
elif not isinstance(base_logger, logging.Logger):
base_logger = _base_log
class _Loggers(dict):
def __missing__(self, key):
if key.startswith("telethon."):
key = key.split(".", maxsplit=1)[1]
return base_logger.getChild(key)
self._log = _Loggers()
# Determine what session object we have
if isinstance(session, str) or session is None:
try:
session = SQLiteSession(session)
except ImportError:
import warnings
warnings.warn(
"The sqlite3 module is not available under this "
"Python installation and no custom session "
"instance was given; using MemorySession.\n"
"You will need to re-login every time unless "
"you use another session storage"
)
session = MemorySession()
elif not isinstance(session, Session):
raise TypeError("The given session must be a str or a Session instance.")
# ':' in session.server_address is True if it's an IPv6 address
if not session.server_address or (":" in session.server_address) != use_ipv6:
session.set_dc(
DEFAULT_DC_ID,
DEFAULT_IPV6_IP if self._use_ipv6 else DEFAULT_IPV4_IP,
DEFAULT_PORT,
)
self.flood_sleep_threshold = flood_sleep_threshold
self.session = session
self.api_id = int(api_id)
self.api_hash = api_hash
if not callable(getattr(self.loop, "sock_connect", None)):
raise TypeError(
"Event loop of type {} lacks `sock_connect`, which is needed to use proxies.\n\n"
"Change the event loop in use to use proxies:\n"
"# https://github.com/LonamiWebs/Telethon/issues/1337\n"
"import asyncio\n"
"asyncio.set_event_loop(asyncio.SelectorEventLoop())".format(
self.loop.__class__.__name__
)
)
if local_addr is not None:
if use_ipv6 is False and ":" in local_addr:
raise TypeError(
"A local IPv6 address must only be used with `use_ipv6=True`."
)
elif use_ipv6 is True and ":" not in local_addr:
raise TypeError(
"`use_ipv6=True` must only be used with a local IPv6 address."
)
self._raise_last_call_error = raise_last_call_error
self._request_retries = request_retries
self._connection_retries = connection_retries
self._retry_delay = retry_delay or 0
self._proxy = proxy
self._local_addr = local_addr
self._timeout = timeout
self._auto_reconnect = auto_reconnect
assert isinstance(connection, type)
self._connection = connection
# noinspection PyUnresolvedReferences
init_proxy = (
None
if not issubclass(connection, TcpMTProxy)
else types.InputClientProxy(*connection.address_info(proxy))
)
# Used on connection. Capture the variables in a lambda since
# exporting clients need to create this InvokeWithLayerRequest.
system = platform.uname()
if system.machine in ("x86_64", "AMD64"):
default_device_model = "PC 64bit"
elif system.machine in ("i386", "i686", "x86"):
default_device_model = "PC 32bit"
else:
default_device_model = system.machine
default_system_version = re.sub(r"-.+", "", system.release)
self._init_request = functions.InitConnectionRequest(
api_id=self.api_id,
device_model=device_model or default_device_model or "Unknown",
system_version=system_version or default_system_version or "1.0",
app_version=app_version or self.__version__,
lang_code=lang_code,
system_lang_code=system_lang_code,
lang_pack=API_PACKS.get(self.api_id, "android"),
query=None,
proxy=init_proxy,
)
# Remember flood-waited requests to avoid making them again
self._flood_waited_requests = {} # type: ignore
# Cache ``{dc_id: (_ExportState, MTProtoSender)}`` for all borrowed senders
self._borrowed_senders = {} # type: ignore
self._borrow_sender_lock = asyncio.Lock()
self._loop = None # only used as a sanity check
self._updates_error = None
self._updates_handle = None
self._keepalive_handle = None
self._last_request = time.time()
self._no_updates = not receive_updates
# Used for non-sequential updates, in order to terminate all pending tasks on disconnect.
self._sequential_updates = sequential_updates
self._event_handler_tasks = set() # type: ignore
self._authorized = None
# Some further state for subclasses
self._event_builders = [] # type: ignore
# {chat_id: {Conversation}}
self._conversations = collections.defaultdict(set) # type: ignore
self._albums = {} # type: ignore
# Default parse mode
self._parse_mode = markdown
# Some fields to easy signing in. Let {phone: hash} be
# a dictionary because the user may change their mind.
self._phone_code_hash = {} # type: ignore
self._phone = None
self._tos = None
# A place to store if channels are a megagroup or not (see `edit_admin`)
self._megagroup_cache = {} # type: ignore
# This is backported from v2 in a very ad-hoc way just to get proper update handling
self._catch_up = catch_up
self._updates_queue = asyncio.Queue() # type: ignore
self._message_box = MessageBox(self._log["messagebox"])
self._mb_entity_cache = (
MbEntityCache()
) # required for proper update handling (to know when to getDifference)
self._entity_cache_limit = entity_cache_limit
self._sender = MTProtoSender(
self.session.auth_key,
loggers=self._log,
retries=self._connection_retries,
delay=self._retry_delay,
auto_reconnect=self._auto_reconnect,
connect_timeout=self._timeout,
auth_key_callback=self._auth_key_callback,
updates_queue=self._updates_queue,
auto_reconnect_callback=self._handle_auto_reconnect,
)

View File

@ -3,13 +3,25 @@ import logging
from pathlib import Path from pathlib import Path
from typing import Self from typing import Self
from telethon import TelegramClient
from telethon.errors import UserDeactivatedBanError, UserDeactivatedError from telethon.errors import UserDeactivatedBanError, UserDeactivatedError
from telethon.sessions import StringSession from telethon.sessions import StringSession
from .base_client import TelegramClient
TelethonBannedError = (UserDeactivatedError, UserDeactivatedBanError) TelethonBannedError = (UserDeactivatedError, UserDeactivatedBanError)
API_PACKS = {
4: "android",
5: "android",
6: "android",
8: "ios",
2834: "macos",
2040: "tdesktop",
17349: "tdesktop",
21724: "android",
16623: "android",
2496: "",
}
class BaseData: class BaseData:
def __init__(self, json_data: dict, raise_error: bool): def __init__(self, json_data: dict, raise_error: bool):
@ -135,7 +147,7 @@ class BaseThon(BaseData):
def __get_client(self) -> TelegramClient: def __get_client(self) -> TelegramClient:
__session = str(self.__item) if self.__item else self.string_session __session = str(self.__item) if self.__item else self.string_session
return TelegramClient( client = TelegramClient(
session=__session, session=__session,
api_id=self.app_id, api_id=self.app_id,
api_hash=self.app_hash, api_hash=self.app_hash,
@ -148,6 +160,9 @@ class BaseThon(BaseData):
proxy=self.proxy, proxy=self.proxy,
timeout=self.__timeout, timeout=self.__timeout,
) )
client._init_request.lang_pack = API_PACKS.get(self.app_id, "android")
return client
async def check(self) -> str: async def check(self) -> str:
try: try: