mirror of
https://github.com/Mayuri-Chan/pyrofork.git
synced 2026-01-04 22:34:52 +00:00
Merge branch 'develop' into asyncio
# Conflicts: # pyrogram/client/client.py # pyrogram/client/ext/base_client.py # pyrogram/client/methods/bots/request_callback_answer.py # pyrogram/session/session.py
This commit is contained in:
commit
5f727cb5a2
8 changed files with 165 additions and 100 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
## Include
|
## Include
|
||||||
include COPYING COPYING.lesser NOTICE requirements.txt requirements_extras.txt
|
include COPYING COPYING.lesser NOTICE requirements.txt
|
||||||
recursive-include compiler *.py *.tl *.tsv *.txt
|
recursive-include compiler *.py *.tl *.tsv *.txt
|
||||||
|
|
||||||
## Exclude
|
## Exclude
|
||||||
|
|
|
||||||
25
README.rst
25
README.rst
|
|
@ -1,7 +1,7 @@
|
||||||
|header|
|
|header|
|
||||||
|
|
||||||
Pyrogram |twitter|
|
Pyrogram
|
||||||
==================
|
========
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
@ -26,8 +26,8 @@ Features
|
||||||
- **Easy to use**: You can easily install Pyrogram using pip and start building your app right away.
|
- **Easy to use**: You can easily install Pyrogram using pip and start building your app right away.
|
||||||
- **High-level**: The low-level details of MTProto are abstracted and automatically handled.
|
- **High-level**: The low-level details of MTProto are abstracted and automatically handled.
|
||||||
- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C.
|
- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C.
|
||||||
- **Updated** to the latest Telegram API version, currently Layer 76 running on MTProto 2.0.
|
- **Updated** to the latest Telegram API version, currently Layer 79 on top of MTProto 2.0.
|
||||||
- **Documented**: Pyrogram API methods are documented and resemble the Telegram Bot API.
|
- **Documented**: The Pyrogram API is well documented and resembles the Telegram Bot API.
|
||||||
- **Full API**, allowing to execute any advanced action an official client is able to do, and more.
|
- **Full API**, allowing to execute any advanced action an official client is able to do, and more.
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
|
|
@ -54,7 +54,7 @@ Getting Started
|
||||||
Contributing
|
Contributing
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Pyrogram is brand new! **You are welcome to try it and help make it better** by either submitting pull
|
Pyrogram is brand new, and **you are welcome to try it and help make it even better** by either submitting pull
|
||||||
requests or reporting issues/bugs as well as suggesting best practices, ideas, enhancements on both code
|
requests or reporting issues/bugs as well as suggesting best practices, ideas, enhancements on both code
|
||||||
and documentation. Any help is appreciated!
|
and documentation. Any help is appreciated!
|
||||||
|
|
||||||
|
|
@ -100,28 +100,25 @@ Copyright & License
|
||||||
</a>
|
</a>
|
||||||
<br><br>
|
<br><br>
|
||||||
<a href="compiler/api/source/main_api.tl">
|
<a href="compiler/api/source/main_api.tl">
|
||||||
<img src="https://media.pyrogram.ml/images/scheme.svg"
|
<img src="https://img.shields.io/badge/SCHEME-LAYER%2079-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||||
alt="Scheme Layer 76">
|
alt="Scheme Layer">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/pyrogram/tgcrypto">
|
<a href="https://github.com/pyrogram/tgcrypto">
|
||||||
<img src="https://media.pyrogram.ml/images/tgcrypto.svg"
|
<img src="https://img.shields.io/badge/TGCRYPTO-V1.0.4-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||||
alt="TgCrypto">
|
alt="TgCrypto">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
.. |twitter| image:: https://media.pyrogram.ml/images/twitter.svg
|
|
||||||
:target: https://twitter.com/intent/tweet?text=Build%20custom%20Telegram%20applications%20with%20Pyrogram&url=https://github.com/pyrogram/pyrogram&hashtags=Telegram,MTProto,Python
|
|
||||||
|
|
||||||
.. |logo| image:: https://pyrogram.ml/images/logo.png
|
.. |logo| image:: https://pyrogram.ml/images/logo.png
|
||||||
:target: https://pyrogram.ml
|
:target: https://pyrogram.ml
|
||||||
:alt: Pyrogram
|
:alt: Pyrogram
|
||||||
|
|
||||||
.. |description| replace:: **Telegram MTProto API Client Library for Python**
|
.. |description| replace:: **Telegram MTProto API Client Library for Python**
|
||||||
|
|
||||||
.. |scheme| image:: https://www.pyrogram.ml/images/scheme.svg
|
.. |scheme| image:: "https://img.shields.io/badge/SCHEME-LAYER%2079-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||||
:target: compiler/api/source/main_api.tl
|
:target: compiler/api/source/main_api.tl
|
||||||
:alt: Scheme Layer 76
|
:alt: Scheme Layer
|
||||||
|
|
||||||
.. |tgcrypto| image:: https://www.pyrogram.ml/images/tgcrypto.svg
|
.. |tgcrypto| image:: "https://img.shields.io/badge/TGCRYPTO-V1.0.4-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||||
:target: https://github.com/pyrogram/tgcrypto
|
:target: https://github.com/pyrogram/tgcrypto
|
||||||
:alt: TgCrypto
|
:alt: TgCrypto
|
||||||
|
|
|
||||||
|
|
@ -14,27 +14,31 @@ Log In
|
||||||
|
|
||||||
To automate the **Log In** process, pass your ``phone_number`` and ``password`` (if you have one) in the Client parameters.
|
To automate the **Log In** process, pass your ``phone_number`` and ``password`` (if you have one) in the Client parameters.
|
||||||
If you want to retrieve the phone code programmatically, pass a callback function in the ``phone_code`` field — this
|
If you want to retrieve the phone code programmatically, pass a callback function in the ``phone_code`` field — this
|
||||||
function must return the correct phone code as string (e.g., "12345") — otherwise, ignore this parameter, Pyrogram will
|
function accepts a single positional argument (phone_number) and must return the correct phone code (e.g., "12345")
|
||||||
ask you to input the phone code manually.
|
— otherwise, ignore this parameter, Pyrogram will ask you to input the phone code manually.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
|
|
||||||
def phone_code_callback():
|
def phone_code_callback(phone_number):
|
||||||
code = ... # Get your code programmatically
|
code = ... # Get your code programmatically
|
||||||
return code # Must be string, e.g., "12345"
|
return code # e.g., "12345"
|
||||||
|
|
||||||
|
|
||||||
app = Client(
|
app = Client(
|
||||||
session_name="example",
|
session_name="example",
|
||||||
phone_number="39**********",
|
phone_number="39**********",
|
||||||
phone_code=phone_code_callback,
|
phone_code=phone_code_callback, # Note the missing parentheses
|
||||||
password="password" # (if you have one)
|
password="password" # (if you have one)
|
||||||
)
|
)
|
||||||
|
|
||||||
app.start()
|
app.start()
|
||||||
|
|
||||||
print(app.get_me())
|
print(app.get_me())
|
||||||
|
|
||||||
app.stop()
|
app.stop()
|
||||||
|
|
||||||
Sign Up
|
Sign Up
|
||||||
|
|
@ -44,23 +48,27 @@ To automate the **Sign Up** process (i.e., automatically create a new Telegram a
|
||||||
``first_name`` and ``last_name`` fields alongside the other parameters; they will be used to automatically create a new
|
``first_name`` and ``last_name`` fields alongside the other parameters; they will be used to automatically create a new
|
||||||
Telegram account in case the phone number you passed is not registered yet.
|
Telegram account in case the phone number you passed is not registered yet.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
|
|
||||||
def phone_code_callback():
|
def phone_code_callback(phone_number):
|
||||||
code = ... # Get your code programmatically
|
code = ... # Get your code programmatically
|
||||||
return code # Must be string, e.g., "12345"
|
return code # e.g., "12345"
|
||||||
|
|
||||||
|
|
||||||
app = Client(
|
app = Client(
|
||||||
session_name="example",
|
session_name="example",
|
||||||
phone_number="39**********",
|
phone_number="39**********",
|
||||||
phone_code=phone_code_callback,
|
phone_code=phone_code_callback, # Note the missing parentheses
|
||||||
first_name="Pyrogram",
|
first_name="Pyrogram",
|
||||||
last_name="" # Can be an empty string
|
last_name="" # Can be an empty string
|
||||||
)
|
)
|
||||||
|
|
||||||
app.start()
|
app.start()
|
||||||
|
|
||||||
print(app.get_me())
|
print(app.get_me())
|
||||||
|
|
||||||
app.stop()
|
app.stop()
|
||||||
|
|
@ -31,7 +31,7 @@ __copyright__ = "Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance
|
||||||
"e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
|
"e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
|
||||||
)
|
)
|
||||||
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
|
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
|
||||||
__version__ = "0.7.5.dev2"
|
__version__ = "0.7.5.dev3"
|
||||||
|
|
||||||
from .api.errors import Error
|
from .api.errors import Error
|
||||||
from .client.types import (
|
from .client.types import (
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,6 @@ from .ext import BaseClient, Syncer, utils
|
||||||
from .handlers import DisconnectHandler
|
from .handlers import DisconnectHandler
|
||||||
from .methods import Methods
|
from .methods import Methods
|
||||||
|
|
||||||
# Custom format for nice looking log lines
|
|
||||||
LOG_FORMAT = "[%(asctime)s.%(msecs)03d] %(filename)s:%(lineno)s %(levelname)s: %(message)s"
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -76,6 +73,26 @@ class Client(Methods, BaseClient):
|
||||||
The *api_hash* part of your Telegram API Key, as string. E.g.: "0123456789abcdef0123456789abcdef"
|
The *api_hash* part of your Telegram API Key, as string. E.g.: "0123456789abcdef0123456789abcdef"
|
||||||
This is an alternative way to pass it if you don't want to use the *config.ini* file.
|
This is an alternative way to pass it if you don't want to use the *config.ini* file.
|
||||||
|
|
||||||
|
app_version (``str``, *optional*):
|
||||||
|
Application version. Defaults to "Pyrogram \U0001f525 vX.Y.Z"
|
||||||
|
This is an alternative way to set it if you don't want to use the *config.ini* file.
|
||||||
|
|
||||||
|
device_model (``str``, *optional*):
|
||||||
|
Device model. Defaults to *platform.python_implementation() + " " + platform.python_version()*
|
||||||
|
This is an alternative way to set it if you don't want to use the *config.ini* file.
|
||||||
|
|
||||||
|
system_version (``str``, *optional*):
|
||||||
|
Operating System version. Defaults to *platform.system() + " " + platform.release()*
|
||||||
|
This is an alternative way to set it if you don't want to use the *config.ini* file.
|
||||||
|
|
||||||
|
system_lang_code (``str``, *optional*):
|
||||||
|
Code of the language used on the system, in ISO 639-1 standard. Defaults to "en".
|
||||||
|
This is an alternative way to set it if you don't want to use the *config.ini* file.
|
||||||
|
|
||||||
|
lang_code (``str``, *optional*):
|
||||||
|
Code of the language used on the client, in ISO 639-1 standard. Defaults to "en".
|
||||||
|
This is an alternative way to set it if you don't want to use the *config.ini* file.
|
||||||
|
|
||||||
proxy (``dict``, *optional*):
|
proxy (``dict``, *optional*):
|
||||||
Your SOCKS5 Proxy settings as dict,
|
Your SOCKS5 Proxy settings as dict,
|
||||||
e.g.: *dict(hostname="11.22.33.44", port=1080, username="user", password="pass")*.
|
e.g.: *dict(hostname="11.22.33.44", port=1080, username="user", password="pass")*.
|
||||||
|
|
@ -92,8 +109,8 @@ class Client(Methods, BaseClient):
|
||||||
entering it manually. Only applicable for new sessions.
|
entering it manually. Only applicable for new sessions.
|
||||||
|
|
||||||
phone_code (``str`` | ``callable``, *optional*):
|
phone_code (``str`` | ``callable``, *optional*):
|
||||||
Pass the phone code as string (for test numbers only), or pass a callback function
|
Pass the phone code as string (for test numbers only), or pass a callback function which accepts
|
||||||
which must return the correct phone code as string (e.g., "12345").
|
a single positional argument *(phone_number)* and must return the correct phone code (e.g., "12345").
|
||||||
Only applicable for new sessions.
|
Only applicable for new sessions.
|
||||||
|
|
||||||
password (``str``, *optional*):
|
password (``str``, *optional*):
|
||||||
|
|
@ -128,6 +145,11 @@ class Client(Methods, BaseClient):
|
||||||
session_name: str,
|
session_name: str,
|
||||||
api_id: int or str = None,
|
api_id: int or str = None,
|
||||||
api_hash: str = None,
|
api_hash: str = None,
|
||||||
|
app_version: str = None,
|
||||||
|
device_model: str = None,
|
||||||
|
system_version: str = None,
|
||||||
|
system_lang_code: str = None,
|
||||||
|
lang_code: str = None,
|
||||||
proxy: dict = None,
|
proxy: dict = None,
|
||||||
test_mode: bool = False,
|
test_mode: bool = False,
|
||||||
phone_number: str = None,
|
phone_number: str = None,
|
||||||
|
|
@ -144,6 +166,11 @@ class Client(Methods, BaseClient):
|
||||||
self.session_name = session_name
|
self.session_name = session_name
|
||||||
self.api_id = int(api_id) if api_id else None
|
self.api_id = int(api_id) if api_id else None
|
||||||
self.api_hash = api_hash
|
self.api_hash = api_hash
|
||||||
|
self.app_version = app_version
|
||||||
|
self.device_model = device_model
|
||||||
|
self.system_version = system_version
|
||||||
|
self.system_lang_code = system_lang_code
|
||||||
|
self.lang_code = lang_code
|
||||||
# TODO: Make code consistent, use underscore for private/protected fields
|
# TODO: Make code consistent, use underscore for private/protected fields
|
||||||
self._proxy = proxy
|
self._proxy = proxy
|
||||||
self.test_mode = test_mode
|
self.test_mode = test_mode
|
||||||
|
|
@ -186,12 +213,9 @@ class Client(Methods, BaseClient):
|
||||||
await self.load_session()
|
await self.load_session()
|
||||||
|
|
||||||
self.session = Session(
|
self.session = Session(
|
||||||
|
self,
|
||||||
self.dc_id,
|
self.dc_id,
|
||||||
self.test_mode,
|
self.auth_key
|
||||||
self._proxy,
|
|
||||||
self.auth_key,
|
|
||||||
self.api_id,
|
|
||||||
client=self
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.session.start()
|
await self.session.start()
|
||||||
|
|
@ -274,6 +298,7 @@ class Client(Methods, BaseClient):
|
||||||
Iterable containing signals the signal handler will listen to.
|
Iterable containing signals the signal handler will listen to.
|
||||||
Defaults to (SIGINT, SIGTERM, SIGABRT).
|
Defaults to (SIGINT, SIGTERM, SIGABRT).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def signal_handler(*args):
|
def signal_handler(*args):
|
||||||
log.info("Stop signal received ({}). Exiting...".format(args[0]))
|
log.info("Stop signal received ({}). Exiting...".format(args[0]))
|
||||||
self.is_idle = False
|
self.is_idle = False
|
||||||
|
|
@ -368,12 +393,9 @@ class Client(Methods, BaseClient):
|
||||||
self.auth_key = await Auth(self.dc_id, self.test_mode, self._proxy).create()
|
self.auth_key = await Auth(self.dc_id, self.test_mode, self._proxy).create()
|
||||||
|
|
||||||
self.session = Session(
|
self.session = Session(
|
||||||
|
self,
|
||||||
self.dc_id,
|
self.dc_id,
|
||||||
self.test_mode,
|
self.auth_key
|
||||||
self._proxy,
|
|
||||||
self.auth_key,
|
|
||||||
self.api_id,
|
|
||||||
client=self
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.session.start()
|
await self.session.start()
|
||||||
|
|
@ -416,12 +438,9 @@ class Client(Methods, BaseClient):
|
||||||
self.auth_key = await Auth(self.dc_id, self.test_mode, self._proxy).create()
|
self.auth_key = await Auth(self.dc_id, self.test_mode, self._proxy).create()
|
||||||
|
|
||||||
self.session = Session(
|
self.session = Session(
|
||||||
|
self,
|
||||||
self.dc_id,
|
self.dc_id,
|
||||||
self.test_mode,
|
self.auth_key
|
||||||
self._proxy,
|
|
||||||
self.auth_key,
|
|
||||||
self.api_id,
|
|
||||||
client=self
|
|
||||||
)
|
)
|
||||||
await self.session.start()
|
await self.session.start()
|
||||||
|
|
||||||
|
|
@ -465,7 +484,7 @@ class Client(Methods, BaseClient):
|
||||||
self.phone_code = (
|
self.phone_code = (
|
||||||
input("Enter phone code: ") if self.phone_code is None
|
input("Enter phone code: ") if self.phone_code is None
|
||||||
else self.phone_code if type(self.phone_code) is str
|
else self.phone_code if type(self.phone_code) is str
|
||||||
else str(self.phone_code())
|
else str(self.phone_code(self.phone_number))
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -807,7 +826,7 @@ class Client(Methods, BaseClient):
|
||||||
|
|
||||||
log.info("UpdatesWorkerTask stopped")
|
log.info("UpdatesWorkerTask stopped")
|
||||||
|
|
||||||
async def send(self, data: Object):
|
async def send(self, data: Object, retries: int = Session.MAX_RETRIES, timeout: float = Session.WAIT_TIMEOUT):
|
||||||
"""Use this method to send Raw Function queries.
|
"""Use this method to send Raw Function queries.
|
||||||
|
|
||||||
This method makes possible to manually call every single Telegram API method in a low-level manner.
|
This method makes possible to manually call every single Telegram API method in a low-level manner.
|
||||||
|
|
@ -818,13 +837,19 @@ class Client(Methods, BaseClient):
|
||||||
data (``Object``):
|
data (``Object``):
|
||||||
The API Scheme function filled with proper arguments.
|
The API Scheme function filled with proper arguments.
|
||||||
|
|
||||||
|
retries (``int``):
|
||||||
|
Number of retries.
|
||||||
|
|
||||||
|
timeout (``float``):
|
||||||
|
Timeout in seconds.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
:class:`Error <pyrogram.Error>`
|
:class:`Error <pyrogram.Error>`
|
||||||
"""
|
"""
|
||||||
if not self.is_started:
|
if not self.is_started:
|
||||||
raise ConnectionError("Client has not been started")
|
raise ConnectionError("Client has not been started")
|
||||||
|
|
||||||
r = await self.session.send(data)
|
r = await self.session.send(data, retries, timeout)
|
||||||
|
|
||||||
self.fetch_peers(getattr(r, "users", []))
|
self.fetch_peers(getattr(r, "users", []))
|
||||||
self.fetch_peers(getattr(r, "chats", []))
|
self.fetch_peers(getattr(r, "chats", []))
|
||||||
|
|
@ -847,6 +872,31 @@ class Client(Methods, BaseClient):
|
||||||
"More info: https://docs.pyrogram.ml/start/ProjectSetup#configuration"
|
"More info: https://docs.pyrogram.ml/start/ProjectSetup#configuration"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for option in {"app_version", "device_model", "system_version", "system_lang_code", "lang_code"}:
|
||||||
|
if getattr(self, option):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
setattr(self, option, Client.APP_VERSION)
|
||||||
|
|
||||||
|
if parser.has_section("pyrogram"):
|
||||||
|
setattr(self, option, parser.get(
|
||||||
|
"pyrogram",
|
||||||
|
option,
|
||||||
|
fallback=getattr(Client, option.upper())
|
||||||
|
))
|
||||||
|
|
||||||
|
if self.lang_code:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.lang_code = Client.LANG_CODE
|
||||||
|
|
||||||
|
if parser.has_section("pyrogram"):
|
||||||
|
self.lang_code = parser.get(
|
||||||
|
"pyrogram",
|
||||||
|
"lang_code",
|
||||||
|
fallback=Client.LANG_CODE
|
||||||
|
)
|
||||||
|
|
||||||
if self._proxy:
|
if self._proxy:
|
||||||
self._proxy["enabled"] = True
|
self._proxy["enabled"] = True
|
||||||
else:
|
else:
|
||||||
|
|
@ -1017,7 +1067,7 @@ class Client(Methods, BaseClient):
|
||||||
file_id = file_id or self.rnd_id()
|
file_id = file_id or self.rnd_id()
|
||||||
md5_sum = md5() if not is_big and not is_missing_part else None
|
md5_sum = md5() if not is_big and not is_missing_part else None
|
||||||
|
|
||||||
session = Session(self.dc_id, self.test_mode, self._proxy, self.auth_key, self.api_id)
|
session = Session(self, self.dc_id, self.auth_key, is_media=True)
|
||||||
await session.start()
|
await session.start()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -1101,11 +1151,10 @@ class Client(Methods, BaseClient):
|
||||||
)
|
)
|
||||||
|
|
||||||
session = Session(
|
session = Session(
|
||||||
|
self,
|
||||||
dc_id,
|
dc_id,
|
||||||
self.test_mode,
|
|
||||||
self._proxy,
|
|
||||||
await Auth(dc_id, self.test_mode, self._proxy).create(),
|
await Auth(dc_id, self.test_mode, self._proxy).create(),
|
||||||
self.api_id
|
is_media=True
|
||||||
)
|
)
|
||||||
|
|
||||||
await session.start()
|
await session.start()
|
||||||
|
|
@ -1120,11 +1169,10 @@ class Client(Methods, BaseClient):
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
session = Session(
|
session = Session(
|
||||||
|
self,
|
||||||
dc_id,
|
dc_id,
|
||||||
self.test_mode,
|
|
||||||
self._proxy,
|
|
||||||
self.auth_key,
|
self.auth_key,
|
||||||
self.api_id
|
is_media=True
|
||||||
)
|
)
|
||||||
|
|
||||||
await session.start()
|
await session.start()
|
||||||
|
|
@ -1190,11 +1238,10 @@ class Client(Methods, BaseClient):
|
||||||
|
|
||||||
if cdn_session is None:
|
if cdn_session is None:
|
||||||
cdn_session = Session(
|
cdn_session = Session(
|
||||||
|
self,
|
||||||
r.dc_id,
|
r.dc_id,
|
||||||
self.test_mode,
|
|
||||||
self._proxy,
|
|
||||||
await Auth(r.dc_id, self.test_mode, self._proxy).create(),
|
await Auth(r.dc_id, self.test_mode, self._proxy).create(),
|
||||||
self.api_id,
|
is_media=True,
|
||||||
is_cdn=True
|
is_cdn=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,32 @@
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import platform
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from pyrogram import __version__
|
||||||
from ..style import Markdown, HTML
|
from ..style import Markdown, HTML
|
||||||
from ...api.core import Object
|
from ...api.core import Object
|
||||||
|
from ...session import Session
|
||||||
from ...session.internals import MsgId
|
from ...session.internals import MsgId
|
||||||
|
|
||||||
|
|
||||||
class BaseClient:
|
class BaseClient:
|
||||||
|
APP_VERSION = "Pyrogram \U0001f525 {}".format(__version__)
|
||||||
|
|
||||||
|
DEVICE_MODEL = "{} {}".format(
|
||||||
|
platform.python_implementation(),
|
||||||
|
platform.python_version()
|
||||||
|
)
|
||||||
|
|
||||||
|
SYSTEM_VERSION = "{} {}".format(
|
||||||
|
platform.system(),
|
||||||
|
platform.release()
|
||||||
|
)
|
||||||
|
|
||||||
|
SYSTEM_LANG_CODE = "en"
|
||||||
|
LANG_CODE = "en"
|
||||||
|
|
||||||
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/joinchat/)([\w-]+)$")
|
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/joinchat/)([\w-]+)$")
|
||||||
BOT_TOKEN_RE = re.compile(r"^\d+:[\w-]+$")
|
BOT_TOKEN_RE = re.compile(r"^\d+:[\w-]+$")
|
||||||
DIALOGS_AT_ONCE = 100
|
DIALOGS_AT_ONCE = 100
|
||||||
|
|
@ -76,7 +94,7 @@ class BaseClient:
|
||||||
|
|
||||||
self.disconnect_handler = None
|
self.disconnect_handler = None
|
||||||
|
|
||||||
def send(self, data: Object):
|
def send(self, data: Object, retries: int = Session.MAX_RETRIES, timeout: float = Session.WAIT_TIMEOUT):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def resolve_peer(self, peer_id: int or str):
|
def resolve_peer(self, peer_id: int or str):
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,8 @@ class RequestCallbackAnswer(BaseClient):
|
||||||
chat_id: int or str,
|
chat_id: int or str,
|
||||||
message_id: int,
|
message_id: int,
|
||||||
callback_data: str):
|
callback_data: str):
|
||||||
"""Use this method to request a callback answer from bots. This is the equivalent of clicking an inline button
|
"""Use this method to request a callback answer from bots. This is the equivalent of clicking an
|
||||||
containing callback data. The answer contains info useful for clients to display a notification at the top of
|
inline button containing callback data.
|
||||||
the chat screen or as an alert.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
chat_id (``int`` | ``str``):
|
chat_id (``int`` | ``str``):
|
||||||
|
|
@ -41,11 +40,21 @@ class RequestCallbackAnswer(BaseClient):
|
||||||
|
|
||||||
callback_data (``str``):
|
callback_data (``str``):
|
||||||
Callback data associated with the inline button you want to get the answer from.
|
Callback data associated with the inline button you want to get the answer from.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The answer containing info useful for clients to display a notification at the top of the chat screen
|
||||||
|
or as an alert.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
``TimeoutError``: If the bot fails to answer within 10 seconds
|
||||||
"""
|
"""
|
||||||
return await self.send(
|
return await self.send(
|
||||||
functions.messages.GetBotCallbackAnswer(
|
functions.messages.GetBotCallbackAnswer(
|
||||||
peer=self.resolve_peer(chat_id),
|
peer=self.resolve_peer(chat_id),
|
||||||
msg_id=message_id,
|
msg_id=message_id,
|
||||||
data=callback_data.encode()
|
data=callback_data.encode()
|
||||||
)
|
),
|
||||||
|
retries=0,
|
||||||
|
timeout=10
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import platform
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
@ -43,19 +42,8 @@ class Result:
|
||||||
|
|
||||||
|
|
||||||
class Session:
|
class Session:
|
||||||
VERSION = __version__
|
INITIAL_SALT = 0x616e67656c696361
|
||||||
APP_VERSION = "Pyrogram \U0001f525 {}".format(VERSION)
|
NET_WORKERS = 1
|
||||||
|
|
||||||
DEVICE_MODEL = "{} {}".format(
|
|
||||||
platform.python_implementation(),
|
|
||||||
platform.python_version()
|
|
||||||
)
|
|
||||||
|
|
||||||
SYSTEM_VERSION = "{} {}".format(
|
|
||||||
platform.system(),
|
|
||||||
platform.release()
|
|
||||||
)
|
|
||||||
|
|
||||||
WAIT_TIMEOUT = 15
|
WAIT_TIMEOUT = 15
|
||||||
MAX_RETRIES = 5
|
MAX_RETRIES = 5
|
||||||
ACKS_THRESHOLD = 8
|
ACKS_THRESHOLD = 8
|
||||||
|
|
@ -78,28 +66,24 @@ class Session:
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
client: pyrogram,
|
||||||
dc_id: int,
|
dc_id: int,
|
||||||
test_mode: bool,
|
|
||||||
proxy: dict,
|
|
||||||
auth_key: bytes,
|
auth_key: bytes,
|
||||||
api_id: int,
|
is_media: bool = False,
|
||||||
is_cdn: bool = False,
|
is_cdn: bool = False):
|
||||||
client: pyrogram = None):
|
|
||||||
if not Session.notice_displayed:
|
if not Session.notice_displayed:
|
||||||
print("Pyrogram v{}, {}".format(__version__, __copyright__))
|
print("Pyrogram v{}, {}".format(__version__, __copyright__))
|
||||||
print("Licensed under the terms of the " + __license__, end="\n\n")
|
print("Licensed under the terms of the " + __license__, end="\n\n")
|
||||||
Session.notice_displayed = True
|
Session.notice_displayed = True
|
||||||
|
|
||||||
self.dc_id = dc_id
|
|
||||||
self.test_mode = test_mode
|
|
||||||
self.proxy = proxy
|
|
||||||
self.api_id = api_id
|
|
||||||
self.is_cdn = is_cdn
|
|
||||||
self.client = client
|
self.client = client
|
||||||
|
self.dc_id = dc_id
|
||||||
|
self.auth_key = auth_key
|
||||||
|
self.is_media = is_media
|
||||||
|
self.is_cdn = is_cdn
|
||||||
|
|
||||||
self.connection = None
|
self.connection = None
|
||||||
|
|
||||||
self.auth_key = auth_key
|
|
||||||
self.auth_key_id = sha1(auth_key).digest()[-8:]
|
self.auth_key_id = sha1(auth_key).digest()[-8:]
|
||||||
|
|
||||||
self.session_id = Long(MsgId())
|
self.session_id = Long(MsgId())
|
||||||
|
|
@ -125,7 +109,7 @@ class Session:
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
while True:
|
while True:
|
||||||
self.connection = Connection(DataCenter(self.dc_id, self.test_mode), self.proxy)
|
self.connection = Connection(DataCenter(self.dc_id, self.client.test_mode), self.client.proxy)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self.connection.connect()
|
await self.connection.connect()
|
||||||
|
|
@ -144,12 +128,14 @@ class Session:
|
||||||
functions.InvokeWithLayer(
|
functions.InvokeWithLayer(
|
||||||
layer,
|
layer,
|
||||||
functions.InitConnection(
|
functions.InitConnection(
|
||||||
self.api_id,
|
api_id=self.client.api_id,
|
||||||
self.DEVICE_MODEL,
|
app_version=self.client.app_version,
|
||||||
self.SYSTEM_VERSION,
|
device_model=self.client.device_model,
|
||||||
self.APP_VERSION,
|
system_version=self.client.system_version,
|
||||||
"en", "", "en",
|
system_lang_code=self.client.system_lang_code,
|
||||||
functions.help.GetConfig(),
|
lang_code=self.client.lang_code,
|
||||||
|
lang_pack="",
|
||||||
|
query=functions.help.GetConfig(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -349,7 +335,7 @@ class Session:
|
||||||
|
|
||||||
log.info("RecvTask stopped")
|
log.info("RecvTask stopped")
|
||||||
|
|
||||||
async def _send(self, data: Object, wait_response: bool = True):
|
async def _send(self, data: Object, wait_response: bool = True, timeout: float = WAIT_TIMEOUT):
|
||||||
message = self.msg_factory(data)
|
message = self.msg_factory(data)
|
||||||
msg_id = message.msg_id
|
msg_id = message.msg_id
|
||||||
|
|
||||||
|
|
@ -372,7 +358,7 @@ class Session:
|
||||||
|
|
||||||
if wait_response:
|
if wait_response:
|
||||||
try:
|
try:
|
||||||
await asyncio.wait_for(self.results[msg_id].event.wait(), self.WAIT_TIMEOUT)
|
await asyncio.wait_for(self.results[msg_id].event.wait(), timeout)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -390,14 +376,14 @@ class Session:
|
||||||
else:
|
else:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
async def send(self, data: Object, retries: int = MAX_RETRIES):
|
async def send(self, data: Object, retries: int = MAX_RETRIES, timeout: float = WAIT_TIMEOUT):
|
||||||
try:
|
try:
|
||||||
await asyncio.wait_for(self.is_connected.wait(), self.WAIT_TIMEOUT)
|
await asyncio.wait_for(self.is_connected.wait(), self.WAIT_TIMEOUT)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return await self._send(data)
|
return await self._send(data, timeout=timeout)
|
||||||
except (OSError, TimeoutError, InternalServerError) as e:
|
except (OSError, TimeoutError, InternalServerError) as e:
|
||||||
if retries == 0:
|
if retries == 0:
|
||||||
raise e from None
|
raise e from None
|
||||||
|
|
@ -408,7 +394,7 @@ class Session:
|
||||||
datetime.now(), type(data)))
|
datetime.now(), type(data)))
|
||||||
|
|
||||||
await asyncio.sleep(0.5)
|
await asyncio.sleep(0.5)
|
||||||
return await self.send(data, retries - 1)
|
return await self.send(data, retries - 1, timeout)
|
||||||
|
|
||||||
# class Result:
|
# class Result:
|
||||||
# def __init__(self):
|
# def __init__(self):
|
||||||
|
|
@ -807,4 +793,4 @@ class Session:
|
||||||
# datetime.now(), type(data)))
|
# datetime.now(), type(data)))
|
||||||
#
|
#
|
||||||
# time.sleep(0.5)
|
# time.sleep(0.5)
|
||||||
# return self.send(data, retries - 1)
|
# return self.send(data, retries - 1, timeout)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue