Pytdbot 0.9.1__tar.gz → 0.9.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytdbot-0.9.1 → pytdbot-0.9.2}/PKG-INFO +4 -3
- {pytdbot-0.9.1 → pytdbot-0.9.2}/Pytdbot.egg-info/PKG-INFO +4 -3
- {pytdbot-0.9.1 → pytdbot-0.9.2}/Pytdbot.egg-info/SOURCES.txt +2 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/README.md +1 -1
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/__init__.py +11 -2
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/client.py +104 -166
- pytdbot-0.9.2/pytdbot/client_manager.py +197 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/handlers/td_updates.py +68 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/methods/td_functions.py +550 -72
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/tdjson/tdjson.py +12 -4
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/types/__init__.py +43 -13
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/types/td_types/bound_methods/message.py +2 -2
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/types/td_types/types.py +898 -84
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/utils/__init__.py +2 -0
- pytdbot-0.9.2/pytdbot/utils/asyncio_utils.py +10 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/LICENSE +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/MANIFEST.in +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/Pytdbot.egg-info/dependency_links.txt +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/Pytdbot.egg-info/requires.txt +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/Pytdbot.egg-info/top_level.txt +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/exception/__init__.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/filters.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/handlers/__init__.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/handlers/decorators.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/handlers/handler.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/methods/__init__.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/methods/methods.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/tdjson/__init__.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/types/plugins/__init__.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/types/td_types/__init__.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/types/td_types/bound_methods/__init__.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/types/td_types/bound_methods/callback_query.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/types/td_types/bound_methods/chatActions.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/types/td_types/bound_methods/file.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/utils/escape.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/utils/json_utils.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/utils/obj_encoder.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/utils/strings.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/utils/text_format.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/pytdbot/utils/webapps.py +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/requirements.txt +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/setup.cfg +0 -0
- {pytdbot-0.9.1 → pytdbot-0.9.2}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: Pytdbot
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.2
|
|
4
4
|
Summary: Easy-to-use asynchronous TDLib wrapper for Python.
|
|
5
5
|
Home-page: https://github.com/pytdbot/client
|
|
6
6
|
Author: AYMEN Mohammed
|
|
@@ -23,13 +23,14 @@ Dynamic: description-content-type
|
|
|
23
23
|
Dynamic: home-page
|
|
24
24
|
Dynamic: keywords
|
|
25
25
|
Dynamic: license
|
|
26
|
+
Dynamic: license-file
|
|
26
27
|
Dynamic: project-url
|
|
27
28
|
Dynamic: provides-extra
|
|
28
29
|
Dynamic: requires-dist
|
|
29
30
|
Dynamic: requires-python
|
|
30
31
|
Dynamic: summary
|
|
31
32
|
|
|
32
|
-
# Pytdbot [](https://pypi.org/project/Pytdbot) [](https://pypi.org/project/Pytdbot) [](https://github.com/tdlib/td) [](https://pepy.tech/project/pytdbot) [](https://t.me/pytdbotchat)
|
|
33
34
|
|
|
34
35
|
Pytdbot (Python TDLib) is an asynchronous [**TDLib**](https://github.com/tdlib/td) wrapper for **Telegram** users/bots written in **Python**.
|
|
35
36
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: Pytdbot
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.2
|
|
4
4
|
Summary: Easy-to-use asynchronous TDLib wrapper for Python.
|
|
5
5
|
Home-page: https://github.com/pytdbot/client
|
|
6
6
|
Author: AYMEN Mohammed
|
|
@@ -23,13 +23,14 @@ Dynamic: description-content-type
|
|
|
23
23
|
Dynamic: home-page
|
|
24
24
|
Dynamic: keywords
|
|
25
25
|
Dynamic: license
|
|
26
|
+
Dynamic: license-file
|
|
26
27
|
Dynamic: project-url
|
|
27
28
|
Dynamic: provides-extra
|
|
28
29
|
Dynamic: requires-dist
|
|
29
30
|
Dynamic: requires-python
|
|
30
31
|
Dynamic: summary
|
|
31
32
|
|
|
32
|
-
# Pytdbot [](https://pypi.org/project/Pytdbot) [](https://pypi.org/project/Pytdbot) [](https://github.com/tdlib/td) [](https://pepy.tech/project/pytdbot) [](https://t.me/pytdbotchat)
|
|
33
34
|
|
|
34
35
|
Pytdbot (Python TDLib) is an asynchronous [**TDLib**](https://github.com/tdlib/td) wrapper for **Telegram** users/bots written in **Python**.
|
|
35
36
|
|
|
@@ -10,6 +10,7 @@ Pytdbot.egg-info/requires.txt
|
|
|
10
10
|
Pytdbot.egg-info/top_level.txt
|
|
11
11
|
pytdbot/__init__.py
|
|
12
12
|
pytdbot/client.py
|
|
13
|
+
pytdbot/client_manager.py
|
|
13
14
|
pytdbot/filters.py
|
|
14
15
|
pytdbot/exception/__init__.py
|
|
15
16
|
pytdbot/handlers/__init__.py
|
|
@@ -31,6 +32,7 @@ pytdbot/types/td_types/bound_methods/chatActions.py
|
|
|
31
32
|
pytdbot/types/td_types/bound_methods/file.py
|
|
32
33
|
pytdbot/types/td_types/bound_methods/message.py
|
|
33
34
|
pytdbot/utils/__init__.py
|
|
35
|
+
pytdbot/utils/asyncio_utils.py
|
|
34
36
|
pytdbot/utils/escape.py
|
|
35
37
|
pytdbot/utils/json_utils.py
|
|
36
38
|
pytdbot/utils/obj_encoder.py
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Pytdbot [](https://pypi.org/project/Pytdbot) [](https://pypi.org/project/Pytdbot) [](https://github.com/tdlib/td) [](https://pepy.tech/project/pytdbot) [](https://t.me/pytdbotchat)
|
|
2
2
|
|
|
3
3
|
Pytdbot (Python TDLib) is an asynchronous [**TDLib**](https://github.com/tdlib/td) wrapper for **Telegram** users/bots written in **Python**.
|
|
4
4
|
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
from . import types, utils, filters, exception
|
|
2
2
|
from .tdjson import TdJson
|
|
3
|
+
from .client_manager import ClientManager
|
|
3
4
|
from .client import Client
|
|
4
5
|
|
|
5
|
-
__all__ = [
|
|
6
|
+
__all__ = [
|
|
7
|
+
"types",
|
|
8
|
+
"utils",
|
|
9
|
+
"filters",
|
|
10
|
+
"exception",
|
|
11
|
+
"TdJson",
|
|
12
|
+
"ClientManager",
|
|
13
|
+
"Client",
|
|
14
|
+
]
|
|
6
15
|
|
|
7
|
-
__version__ = "0.9.
|
|
16
|
+
__version__ = "0.9.2"
|
|
8
17
|
__copyright__ = "Copyright (c) 2022-2025 Pytdbot, AYMENJD"
|
|
9
18
|
__license__ = "MIT License"
|
|
10
19
|
|
|
@@ -1,45 +1,37 @@
|
|
|
1
|
-
import signal
|
|
2
|
-
import pytdbot
|
|
3
1
|
import asyncio
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
from
|
|
2
|
+
import signal
|
|
3
|
+
from importlib import import_module
|
|
4
|
+
from json import dumps
|
|
5
|
+
from logging import DEBUG, getLogger
|
|
7
6
|
from os.path import join as join_path
|
|
8
7
|
from pathlib import Path
|
|
9
|
-
from
|
|
10
|
-
|
|
11
|
-
from typing import Callable,
|
|
12
|
-
from logging import getLogger, DEBUG
|
|
8
|
+
from platform import python_implementation, python_version
|
|
9
|
+
from threading import current_thread, main_thread
|
|
10
|
+
from typing import Callable, Dict, Union
|
|
13
11
|
|
|
12
|
+
import aio_pika
|
|
14
13
|
from deepdiff import DeepDiff
|
|
15
|
-
from concurrent.futures import ThreadPoolExecutor
|
|
16
|
-
from threading import current_thread, main_thread
|
|
17
|
-
from json import dumps
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
from .methods import Methods
|
|
22
|
-
from .types import Plugins, LogStream
|
|
15
|
+
import pytdbot
|
|
16
|
+
|
|
23
17
|
from . import types
|
|
18
|
+
from .client_manager import ClientManager
|
|
19
|
+
from .exception import AuthorizationError, StopHandlers
|
|
24
20
|
from .filters import Filter
|
|
25
|
-
from .
|
|
21
|
+
from .handlers import Decorators, Handler
|
|
22
|
+
from .methods import Methods
|
|
23
|
+
from .types import LogStream, Plugins
|
|
26
24
|
from .utils import (
|
|
27
25
|
create_extra_id,
|
|
28
|
-
|
|
29
|
-
json_dumps,
|
|
26
|
+
dict_to_obj,
|
|
30
27
|
get_bot_id_from_token,
|
|
28
|
+
get_running_loop,
|
|
29
|
+
json_dumps,
|
|
30
|
+
json_loads,
|
|
31
31
|
obj_to_dict,
|
|
32
|
-
dict_to_obj,
|
|
33
32
|
)
|
|
34
33
|
|
|
35
34
|
|
|
36
|
-
def get_running_loop():
|
|
37
|
-
try:
|
|
38
|
-
return asyncio.get_running_loop()
|
|
39
|
-
except RuntimeError:
|
|
40
|
-
return asyncio.new_event_loop()
|
|
41
|
-
|
|
42
|
-
|
|
43
35
|
class Client(Decorators, Methods):
|
|
44
36
|
r"""Pytdbot, a TDLib client
|
|
45
37
|
|
|
@@ -136,6 +128,7 @@ class Client(Decorators, Methods):
|
|
|
136
128
|
no_updates: bool = False,
|
|
137
129
|
td_verbosity: int = 2,
|
|
138
130
|
td_log: LogStream = None,
|
|
131
|
+
user_bot: bool = False,
|
|
139
132
|
) -> None:
|
|
140
133
|
self.__api_id = api_id
|
|
141
134
|
self.__api_hash = api_hash
|
|
@@ -164,9 +157,17 @@ class Client(Decorators, Methods):
|
|
|
164
157
|
self.workers = workers
|
|
165
158
|
self.no_updates = no_updates
|
|
166
159
|
self.queue = asyncio.Queue()
|
|
167
|
-
self.
|
|
160
|
+
self.user_bot = user_bot
|
|
161
|
+
self.my_id = (
|
|
162
|
+
get_bot_id_from_token(self.__token)
|
|
163
|
+
if isinstance(self.__token, str)
|
|
164
|
+
else None
|
|
165
|
+
)
|
|
166
|
+
self.client_id = None
|
|
167
|
+
self.client_manager = None
|
|
168
168
|
self.logger = getLogger(f"{__name__}:{self.my_id or 0}")
|
|
169
169
|
self.td_verbosity = td_verbosity
|
|
170
|
+
self.td_log = td_log
|
|
170
171
|
self.connection_state: str = None
|
|
171
172
|
self.is_running = None
|
|
172
173
|
self.me: types.User = None
|
|
@@ -178,8 +179,6 @@ class Client(Decorators, Methods):
|
|
|
178
179
|
|
|
179
180
|
self._handlers = {"initializer": [], "finalizer": []}
|
|
180
181
|
self._results: Dict[str, asyncio.Future] = {}
|
|
181
|
-
self._tdjson = None if self.is_rabbitmq else TdJson(lib_path, td_verbosity)
|
|
182
|
-
self.__listen_loop_task = None
|
|
183
182
|
self._workers_tasks = None
|
|
184
183
|
self.__authorization_state = None
|
|
185
184
|
self.__cache = {"is_coro_filter": {}}
|
|
@@ -191,9 +190,14 @@ class Client(Decorators, Methods):
|
|
|
191
190
|
"updateOption": self.__handle_update_option,
|
|
192
191
|
"updateUser": self.__handle_update_user,
|
|
193
192
|
}
|
|
194
|
-
self.
|
|
193
|
+
self.__is_queue_worker = False
|
|
195
194
|
self.__is_closing = False
|
|
196
195
|
|
|
196
|
+
# RabbitMQ
|
|
197
|
+
self.__rqueues = None
|
|
198
|
+
self.__rconnection = None
|
|
199
|
+
self.__rchannel = None
|
|
200
|
+
|
|
197
201
|
self.loop = (
|
|
198
202
|
loop if isinstance(loop, asyncio.AbstractEventLoop) else get_running_loop()
|
|
199
203
|
)
|
|
@@ -201,16 +205,10 @@ class Client(Decorators, Methods):
|
|
|
201
205
|
if plugins is not None:
|
|
202
206
|
self._load_plugins()
|
|
203
207
|
|
|
204
|
-
if isinstance(td_log, LogStream) and not self.is_rabbitmq:
|
|
205
|
-
self._tdjson.execute(
|
|
206
|
-
{"@type": "setLogStream", "log_stream": obj_to_dict(td_log)}
|
|
207
|
-
)
|
|
208
|
-
|
|
209
208
|
self.logger.info(f"Pytdbot v{pytdbot.VERSION}")
|
|
210
209
|
|
|
211
210
|
async def __aenter__(self):
|
|
212
211
|
await self.start()
|
|
213
|
-
await self.login()
|
|
214
212
|
return self
|
|
215
213
|
|
|
216
214
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
@@ -225,21 +223,27 @@ class Client(Decorators, Methods):
|
|
|
225
223
|
|
|
226
224
|
return self.__authorization_state
|
|
227
225
|
|
|
228
|
-
async def start(self
|
|
229
|
-
r"""Start pytdbot client
|
|
230
|
-
|
|
231
|
-
Parameters:
|
|
232
|
-
login (``bool``, *optional*):
|
|
233
|
-
Login after start. Default is ``True``
|
|
234
|
-
"""
|
|
226
|
+
async def start(self) -> None:
|
|
227
|
+
r"""Start pytdbot client"""
|
|
235
228
|
|
|
236
229
|
if not self.is_running:
|
|
237
230
|
self.logger.info("Starting pytdbot client...")
|
|
238
231
|
|
|
232
|
+
if not self.client_manager:
|
|
233
|
+
self.client_manager = ClientManager(
|
|
234
|
+
self, self.lib_path, self.td_verbosity, loop=self.loop
|
|
235
|
+
)
|
|
236
|
+
await self.client_manager.start()
|
|
237
|
+
|
|
238
|
+
if isinstance(self.td_log, LogStream) and not self.is_rabbitmq:
|
|
239
|
+
await self.__send(
|
|
240
|
+
{"@type": "setLogStream", "log_stream": obj_to_dict(self.td_log)}
|
|
241
|
+
)
|
|
242
|
+
|
|
239
243
|
if isinstance(self.workers, int):
|
|
240
244
|
self._workers_tasks = [
|
|
241
245
|
self.loop.create_task(self._queue_update_worker())
|
|
242
|
-
for
|
|
246
|
+
for _ in range(self.workers)
|
|
243
247
|
]
|
|
244
248
|
self.__is_queue_worker = True
|
|
245
249
|
|
|
@@ -249,45 +253,13 @@ class Client(Decorators, Methods):
|
|
|
249
253
|
self.logger.info("Started with unlimited updates processes")
|
|
250
254
|
|
|
251
255
|
if self.is_rabbitmq:
|
|
252
|
-
await self.
|
|
253
|
-
else:
|
|
254
|
-
self.
|
|
255
|
-
|
|
256
|
-
if login:
|
|
257
|
-
await self.login()
|
|
258
|
-
|
|
259
|
-
async def login(self) -> None:
|
|
260
|
-
r"""Login to Telegram."""
|
|
261
|
-
|
|
262
|
-
if not self.__token or (self.is_authenticated or self.is_rabbitmq):
|
|
263
|
-
return
|
|
264
|
-
|
|
265
|
-
self.__login = True
|
|
266
|
-
|
|
267
|
-
await self.getOption("version") # Ping TDLib to start authorization process
|
|
268
|
-
|
|
269
|
-
while self.authorization_state != "authorizationStateReady":
|
|
270
|
-
await asyncio.sleep(0.1)
|
|
271
|
-
if self.authorization_state == "authorizationStateClosed":
|
|
272
|
-
return
|
|
273
|
-
|
|
274
|
-
if not self.is_running:
|
|
275
|
-
return
|
|
276
|
-
|
|
277
|
-
self.me = await self.getMe()
|
|
278
|
-
if isinstance(self.me, types.Error):
|
|
279
|
-
self.logger.error(f"Get me error: {self.me.message}")
|
|
280
|
-
|
|
281
|
-
self.is_authenticated = True
|
|
256
|
+
await self.__start_rabbitmq()
|
|
257
|
+
else: # client_manager
|
|
258
|
+
self.is_running = True
|
|
282
259
|
|
|
283
|
-
self.
|
|
284
|
-
"
|
|
285
|
-
|
|
286
|
-
str(self.me.id)
|
|
287
|
-
if not self.me.usernames
|
|
288
|
-
else "@" + self.me.usernames.editable_username,
|
|
289
|
-
)
|
|
290
|
-
)
|
|
260
|
+
self.loop.create_task(
|
|
261
|
+
self.getOption("version")
|
|
262
|
+
) # Ping TDLib to start processing updates
|
|
291
263
|
|
|
292
264
|
def add_handler(
|
|
293
265
|
self,
|
|
@@ -351,13 +323,11 @@ class Client(Decorators, Methods):
|
|
|
351
323
|
|
|
352
324
|
if not isinstance(func, Callable):
|
|
353
325
|
raise TypeError("func must be callable")
|
|
354
|
-
for
|
|
355
|
-
for handler in
|
|
326
|
+
for _, handlers in self._handlers.items():
|
|
327
|
+
for handler in handlers.copy():
|
|
356
328
|
if handler.func == func:
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
key=lambda x: (x.position is None, x.position)
|
|
360
|
-
)
|
|
329
|
+
handlers.remove(handler)
|
|
330
|
+
handlers.sort(key=lambda x: (x.position is None, x.position))
|
|
361
331
|
return True
|
|
362
332
|
return False
|
|
363
333
|
|
|
@@ -466,7 +436,7 @@ class Client(Decorators, Methods):
|
|
|
466
436
|
|
|
467
437
|
return await self.invoke(kwargs)
|
|
468
438
|
|
|
469
|
-
def run(self
|
|
439
|
+
def run(self) -> None:
|
|
470
440
|
r"""Start the client and block until the client is stopped
|
|
471
441
|
|
|
472
442
|
Example:
|
|
@@ -481,15 +451,11 @@ class Client(Decorators, Methods):
|
|
|
481
451
|
await update.reply_text('Hello!')
|
|
482
452
|
|
|
483
453
|
client.run()
|
|
484
|
-
|
|
485
|
-
Parameters:
|
|
486
|
-
login (``bool``, *optional*):
|
|
487
|
-
Login after start. Default is ``True``
|
|
488
454
|
"""
|
|
489
455
|
|
|
490
456
|
self._register_signal_handlers()
|
|
491
457
|
|
|
492
|
-
self.loop.run_until_complete(self.start(
|
|
458
|
+
self.loop.run_until_complete(self.start())
|
|
493
459
|
self.loop.run_until_complete(self.idle())
|
|
494
460
|
|
|
495
461
|
async def idle(self):
|
|
@@ -534,6 +500,9 @@ class Client(Decorators, Methods):
|
|
|
534
500
|
|
|
535
501
|
self.__stop_client()
|
|
536
502
|
|
|
503
|
+
if not self.client_manager.start_clients_on_add:
|
|
504
|
+
await self.client_manager.close()
|
|
505
|
+
|
|
537
506
|
self.logger.info("Instance closed")
|
|
538
507
|
|
|
539
508
|
return True
|
|
@@ -552,11 +521,7 @@ class Client(Decorators, Methods):
|
|
|
552
521
|
return result
|
|
553
522
|
|
|
554
523
|
async def __send(self, request: dict) -> None:
|
|
555
|
-
if
|
|
556
|
-
self._tdjson.send(
|
|
557
|
-
request
|
|
558
|
-
) # tdjson.send is non-blocking method, So we don't need run_in_executor. This improves performance
|
|
559
|
-
else:
|
|
524
|
+
if self.is_rabbitmq:
|
|
560
525
|
await self.__rchannel.default_exchange.publish(
|
|
561
526
|
aio_pika.Message(
|
|
562
527
|
json_dumps(request, encode=True),
|
|
@@ -564,8 +529,13 @@ class Client(Decorators, Methods):
|
|
|
564
529
|
),
|
|
565
530
|
routing_key=self.__rqueues["requests"].name,
|
|
566
531
|
)
|
|
532
|
+
else:
|
|
533
|
+
self.client_manager.send(self.client_id, request)
|
|
567
534
|
|
|
568
535
|
def _check_init_args(self):
|
|
536
|
+
if self.user_bot:
|
|
537
|
+
return
|
|
538
|
+
|
|
569
539
|
if not self.is_rabbitmq:
|
|
570
540
|
if not isinstance(self.__api_id, int):
|
|
571
541
|
raise TypeError("api_id must be an int")
|
|
@@ -657,31 +627,7 @@ class Client(Decorators, Methods):
|
|
|
657
627
|
self.__cache["is_coro_filter"][func] = is_coro
|
|
658
628
|
return is_coro
|
|
659
629
|
|
|
660
|
-
async def
|
|
661
|
-
if self.is_rabbitmq:
|
|
662
|
-
return
|
|
663
|
-
|
|
664
|
-
with ThreadPoolExecutor(1, "pytdbot_listener") as thread:
|
|
665
|
-
try:
|
|
666
|
-
self.is_running = True
|
|
667
|
-
self.logger.info("Listening to updates...")
|
|
668
|
-
|
|
669
|
-
while self.is_running:
|
|
670
|
-
update = await self.loop.run_in_executor(
|
|
671
|
-
thread,
|
|
672
|
-
self._tdjson.receive,
|
|
673
|
-
1.0, # Seconds
|
|
674
|
-
)
|
|
675
|
-
if update is None:
|
|
676
|
-
continue
|
|
677
|
-
self.loop.create_task(self._process_update(update))
|
|
678
|
-
|
|
679
|
-
except Exception:
|
|
680
|
-
self.logger.exception("Exception in __listen_loop")
|
|
681
|
-
finally:
|
|
682
|
-
self.is_running = False
|
|
683
|
-
|
|
684
|
-
async def _process_update(self, update):
|
|
630
|
+
async def process_update(self, update):
|
|
685
631
|
if not update:
|
|
686
632
|
self.logger.warning("Received None update")
|
|
687
633
|
return
|
|
@@ -784,7 +730,8 @@ class Client(Decorators, Methods):
|
|
|
784
730
|
async def _handle_update(self, update):
|
|
785
731
|
if update.getType() in self._handlers:
|
|
786
732
|
if (
|
|
787
|
-
|
|
733
|
+
not self.user_bot
|
|
734
|
+
and isinstance(update, types.UpdateNewMessage)
|
|
788
735
|
and update.message.is_outgoing
|
|
789
736
|
):
|
|
790
737
|
return
|
|
@@ -872,13 +819,23 @@ class Client(Decorators, Methods):
|
|
|
872
819
|
f"Authorization state changed to {self.authorization_state.removeprefix('authorizationState')}"
|
|
873
820
|
)
|
|
874
821
|
|
|
875
|
-
if self.
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
822
|
+
if self.authorization_state == "authorizationStateWaitTdlibParameters":
|
|
823
|
+
await self._set_options()
|
|
824
|
+
await self.set_td_parameters()
|
|
825
|
+
elif self.authorization_state == "authorizationStateWaitPhoneNumber":
|
|
826
|
+
self._print_welcome()
|
|
827
|
+
await self.__handle_authorization_state_wait_phone_number()
|
|
828
|
+
elif self.authorization_state == "authorizationStateReady":
|
|
829
|
+
self.is_authenticated = True
|
|
830
|
+
|
|
831
|
+
self.me = await self.getMe()
|
|
832
|
+
if isinstance(self.me, types.Error):
|
|
833
|
+
self.logger.error(f"Get me error: {self.me.message}")
|
|
834
|
+
|
|
835
|
+
self.logger.info(
|
|
836
|
+
f"Logged in as {self.me.first_name} "
|
|
837
|
+
f"{str(self.me.id) if not self.me.usernames else '@' + self.me.usernames.editable_username}"
|
|
838
|
+
)
|
|
882
839
|
|
|
883
840
|
if (
|
|
884
841
|
self.authorization_state == "authorizationStateClosed"
|
|
@@ -942,7 +899,7 @@ class Client(Decorators, Methods):
|
|
|
942
899
|
f"Could not connect to TDLib Server after {delay * retries} seconds timeout"
|
|
943
900
|
)
|
|
944
901
|
|
|
945
|
-
async def
|
|
902
|
+
async def __start_rabbitmq(self):
|
|
946
903
|
self.__rconnection = await aio_pika.connect_robust(
|
|
947
904
|
self.__rabbitmq_url,
|
|
948
905
|
client_properties={
|
|
@@ -979,19 +936,7 @@ class Client(Decorators, Methods):
|
|
|
979
936
|
for update in res.updates:
|
|
980
937
|
# when using obj_to_dict the key "@client_id" won't exists
|
|
981
938
|
# since it's not part of the object
|
|
982
|
-
await self.
|
|
983
|
-
|
|
984
|
-
self.me = await self.getMe()
|
|
985
|
-
self.is_authenticated = True
|
|
986
|
-
|
|
987
|
-
self.logger.info(
|
|
988
|
-
"Logged in as {} {}".format(
|
|
989
|
-
self.me.first_name,
|
|
990
|
-
str(self.me.id)
|
|
991
|
-
if not self.me.usernames
|
|
992
|
-
else "@" + self.me.usernames.editable_username,
|
|
993
|
-
)
|
|
994
|
-
)
|
|
939
|
+
await self.process_update(obj_to_dict(update))
|
|
995
940
|
|
|
996
941
|
if not self.no_updates:
|
|
997
942
|
await self.__rqueues["updates"].consume(self.__on_update, no_ack=True)
|
|
@@ -999,20 +944,16 @@ class Client(Decorators, Methods):
|
|
|
999
944
|
await self.__rqueues["notify"].consume(self.__on_update, no_ack=True)
|
|
1000
945
|
|
|
1001
946
|
async def __handle_rabbitmq_message(self, message: aio_pika.IncomingMessage):
|
|
1002
|
-
await self.
|
|
947
|
+
await self.process_update(json_loads(message.body))
|
|
1003
948
|
|
|
1004
949
|
async def __on_update(self, update):
|
|
1005
950
|
self.loop.create_task(self.__handle_rabbitmq_message(update))
|
|
1006
951
|
|
|
1007
952
|
async def __handle_update_user(self, update: types.UpdateUser):
|
|
1008
|
-
if self.is_authenticated and update.user.id == self.me.id:
|
|
953
|
+
if self.is_authenticated and self.me and update.user.id == self.me.id:
|
|
1009
954
|
self.logger.info(
|
|
1010
|
-
"Updating {}
|
|
1011
|
-
|
|
1012
|
-
str(self.me.id)
|
|
1013
|
-
if not self.me.usernames
|
|
1014
|
-
else "@" + self.me.usernames.editable_username,
|
|
1015
|
-
)
|
|
955
|
+
f"Updating {self.me.first_name} "
|
|
956
|
+
f"({str(self.me.id) if not self.me.usernames else '@' + self.me.usernames.editable_username}) info"
|
|
1016
957
|
)
|
|
1017
958
|
|
|
1018
959
|
try:
|
|
@@ -1042,28 +983,25 @@ class Client(Decorators, Methods):
|
|
|
1042
983
|
for worker_task in self._workers_tasks:
|
|
1043
984
|
worker_task.cancel()
|
|
1044
985
|
|
|
1045
|
-
if self.__listen_loop_task:
|
|
1046
|
-
self.__listen_loop_task.cancel()
|
|
1047
|
-
|
|
1048
986
|
def _register_signal_handlers(self):
|
|
1049
987
|
def _handle_signal():
|
|
1050
988
|
self.loop.create_task(self.stop())
|
|
1051
|
-
for sig in
|
|
989
|
+
for sig in (
|
|
1052
990
|
signal.SIGINT,
|
|
1053
991
|
signal.SIGTERM,
|
|
1054
992
|
signal.SIGABRT,
|
|
1055
993
|
signal.SIGSEGV,
|
|
1056
|
-
|
|
994
|
+
):
|
|
1057
995
|
self.loop.remove_signal_handler(sig)
|
|
1058
996
|
|
|
1059
997
|
if current_thread() is main_thread():
|
|
1060
998
|
try:
|
|
1061
|
-
for sig in
|
|
999
|
+
for sig in (
|
|
1062
1000
|
signal.SIGINT,
|
|
1063
1001
|
signal.SIGTERM,
|
|
1064
1002
|
signal.SIGABRT,
|
|
1065
1003
|
signal.SIGSEGV,
|
|
1066
|
-
|
|
1004
|
+
):
|
|
1067
1005
|
self.loop.add_signal_handler(sig, _handle_signal)
|
|
1068
1006
|
except NotImplementedError: # Windows dosen't support add_signal_handler
|
|
1069
1007
|
pass
|
|
@@ -1082,12 +1020,12 @@ def deepdiff(self, d1, d2):
|
|
|
1082
1020
|
|
|
1083
1021
|
deep = DeepDiff(d1, d2, ignore_order=True, view="tree")
|
|
1084
1022
|
|
|
1085
|
-
for parent in deep.
|
|
1086
|
-
for diff in
|
|
1023
|
+
for parent, diffs in deep.items():
|
|
1024
|
+
for diff in diffs:
|
|
1087
1025
|
difflist = diff.path(output_format="list")
|
|
1088
|
-
key = ".".join(str
|
|
1026
|
+
key = ".".join(map(str, difflist))
|
|
1089
1027
|
|
|
1090
|
-
if parent in
|
|
1028
|
+
if parent in ("dictionary_item_added", "values_changed"):
|
|
1091
1029
|
self.logger.info(f"{key} changed to {diff.t2}")
|
|
1092
1030
|
elif parent == "dictionary_item_removed":
|
|
1093
1031
|
self.logger.info(f"{key} removed")
|