Pytdbot 0.9.2.dev2__tar.gz → 0.9.2.dev4__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.2.dev2 → pytdbot-0.9.2.dev4}/PKG-INFO +2 -2
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/Pytdbot.egg-info/PKG-INFO +2 -2
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/Pytdbot.egg-info/SOURCES.txt +2 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/README.md +1 -1
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/__init__.py +11 -2
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/client.py +89 -170
- pytdbot-0.9.2.dev4/pytdbot/client_manager.py +197 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/handlers/td_updates.py +68 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/methods/td_functions.py +550 -72
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/tdjson/tdjson.py +12 -4
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/types/__init__.py +43 -13
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/types/td_types/types.py +898 -84
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/utils/__init__.py +2 -0
- pytdbot-0.9.2.dev4/pytdbot/utils/asyncio_utils.py +10 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/LICENSE +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/MANIFEST.in +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/Pytdbot.egg-info/dependency_links.txt +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/Pytdbot.egg-info/requires.txt +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/Pytdbot.egg-info/top_level.txt +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/exception/__init__.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/filters.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/handlers/__init__.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/handlers/decorators.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/handlers/handler.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/methods/__init__.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/methods/methods.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/tdjson/__init__.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/types/plugins/__init__.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/types/td_types/__init__.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/types/td_types/bound_methods/__init__.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/types/td_types/bound_methods/callback_query.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/types/td_types/bound_methods/chatActions.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/types/td_types/bound_methods/file.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/types/td_types/bound_methods/message.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/utils/escape.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/utils/json_utils.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/utils/obj_encoder.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/utils/strings.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/utils/text_format.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/pytdbot/utils/webapps.py +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/requirements.txt +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/setup.cfg +0 -0
- {pytdbot-0.9.2.dev2 → pytdbot-0.9.2.dev4}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Pytdbot
|
|
3
|
-
Version: 0.9.2.
|
|
3
|
+
Version: 0.9.2.dev4
|
|
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
|
|
@@ -30,7 +30,7 @@ Dynamic: requires-dist
|
|
|
30
30
|
Dynamic: requires-python
|
|
31
31
|
Dynamic: summary
|
|
32
32
|
|
|
33
|
-
# 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)
|
|
34
34
|
|
|
35
35
|
Pytdbot (Python TDLib) is an asynchronous [**TDLib**](https://github.com/tdlib/td) wrapper for **Telegram** users/bots written in **Python**.
|
|
36
36
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Pytdbot
|
|
3
|
-
Version: 0.9.2.
|
|
3
|
+
Version: 0.9.2.dev4
|
|
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
|
|
@@ -30,7 +30,7 @@ Dynamic: requires-dist
|
|
|
30
30
|
Dynamic: requires-python
|
|
31
31
|
Dynamic: summary
|
|
32
32
|
|
|
33
|
-
# 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)
|
|
34
34
|
|
|
35
35
|
Pytdbot (Python TDLib) is an asynchronous [**TDLib**](https://github.com/tdlib/td) wrapper for **Telegram** users/bots written in **Python**.
|
|
36
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.2.
|
|
16
|
+
__version__ = "0.9.2.dev4"
|
|
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
|
|
|
@@ -171,8 +163,11 @@ class Client(Decorators, Methods):
|
|
|
171
163
|
if isinstance(self.__token, str)
|
|
172
164
|
else None
|
|
173
165
|
)
|
|
166
|
+
self.client_id = None
|
|
167
|
+
self.client_manager = None
|
|
174
168
|
self.logger = getLogger(f"{__name__}:{self.my_id or 0}")
|
|
175
169
|
self.td_verbosity = td_verbosity
|
|
170
|
+
self.td_log = td_log
|
|
176
171
|
self.connection_state: str = None
|
|
177
172
|
self.is_running = None
|
|
178
173
|
self.me: types.User = None
|
|
@@ -184,8 +179,6 @@ class Client(Decorators, Methods):
|
|
|
184
179
|
|
|
185
180
|
self._handlers = {"initializer": [], "finalizer": []}
|
|
186
181
|
self._results: Dict[str, asyncio.Future] = {}
|
|
187
|
-
self._tdjson = None if self.is_rabbitmq else TdJson(lib_path, td_verbosity)
|
|
188
|
-
self.__listen_loop_task = None
|
|
189
182
|
self._workers_tasks = None
|
|
190
183
|
self.__authorization_state = None
|
|
191
184
|
self.__cache = {"is_coro_filter": {}}
|
|
@@ -197,9 +190,14 @@ class Client(Decorators, Methods):
|
|
|
197
190
|
"updateOption": self.__handle_update_option,
|
|
198
191
|
"updateUser": self.__handle_update_user,
|
|
199
192
|
}
|
|
200
|
-
self.
|
|
193
|
+
self.__is_queue_worker = False
|
|
201
194
|
self.__is_closing = False
|
|
202
195
|
|
|
196
|
+
# RabbitMQ
|
|
197
|
+
self.__rqueues = None
|
|
198
|
+
self.__rconnection = None
|
|
199
|
+
self.__rchannel = None
|
|
200
|
+
|
|
203
201
|
self.loop = (
|
|
204
202
|
loop if isinstance(loop, asyncio.AbstractEventLoop) else get_running_loop()
|
|
205
203
|
)
|
|
@@ -207,16 +205,10 @@ class Client(Decorators, Methods):
|
|
|
207
205
|
if plugins is not None:
|
|
208
206
|
self._load_plugins()
|
|
209
207
|
|
|
210
|
-
if isinstance(td_log, LogStream) and not self.is_rabbitmq:
|
|
211
|
-
self._tdjson.execute(
|
|
212
|
-
{"@type": "setLogStream", "log_stream": obj_to_dict(td_log)}
|
|
213
|
-
)
|
|
214
|
-
|
|
215
208
|
self.logger.info(f"Pytdbot v{pytdbot.VERSION}")
|
|
216
209
|
|
|
217
210
|
async def __aenter__(self):
|
|
218
211
|
await self.start()
|
|
219
|
-
await self.login()
|
|
220
212
|
return self
|
|
221
213
|
|
|
222
214
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
@@ -231,24 +223,27 @@ class Client(Decorators, Methods):
|
|
|
231
223
|
|
|
232
224
|
return self.__authorization_state
|
|
233
225
|
|
|
234
|
-
async def start(self
|
|
235
|
-
r"""Start pytdbot client
|
|
236
|
-
|
|
237
|
-
Parameters:
|
|
238
|
-
login (``bool``, *optional*):
|
|
239
|
-
Login after start. Default is ``True``
|
|
240
|
-
"""
|
|
241
|
-
|
|
242
|
-
if self.user_bot:
|
|
243
|
-
login = False
|
|
226
|
+
async def start(self) -> None:
|
|
227
|
+
r"""Start pytdbot client"""
|
|
244
228
|
|
|
245
229
|
if not self.is_running:
|
|
246
230
|
self.logger.info("Starting pytdbot client...")
|
|
247
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
|
+
|
|
248
243
|
if isinstance(self.workers, int):
|
|
249
244
|
self._workers_tasks = [
|
|
250
245
|
self.loop.create_task(self._queue_update_worker())
|
|
251
|
-
for
|
|
246
|
+
for _ in range(self.workers)
|
|
252
247
|
]
|
|
253
248
|
self.__is_queue_worker = True
|
|
254
249
|
|
|
@@ -258,52 +253,14 @@ class Client(Decorators, Methods):
|
|
|
258
253
|
self.logger.info("Started with unlimited updates processes")
|
|
259
254
|
|
|
260
255
|
if self.is_rabbitmq:
|
|
261
|
-
await self.
|
|
262
|
-
else:
|
|
263
|
-
self.
|
|
256
|
+
await self.__start_rabbitmq()
|
|
257
|
+
else: # client_manager
|
|
258
|
+
self.is_running = True
|
|
264
259
|
|
|
265
260
|
self.loop.create_task(
|
|
266
261
|
self.getOption("version")
|
|
267
262
|
) # Ping TDLib to start processing updates
|
|
268
263
|
|
|
269
|
-
if login:
|
|
270
|
-
await self.login()
|
|
271
|
-
|
|
272
|
-
async def login(self) -> None:
|
|
273
|
-
r"""Login to Telegram."""
|
|
274
|
-
|
|
275
|
-
if (
|
|
276
|
-
not self.__token
|
|
277
|
-
or self.user_bot
|
|
278
|
-
or (self.is_authenticated or self.is_rabbitmq)
|
|
279
|
-
):
|
|
280
|
-
return
|
|
281
|
-
|
|
282
|
-
self.__login = True
|
|
283
|
-
|
|
284
|
-
while self.authorization_state != "authorizationStateReady":
|
|
285
|
-
await asyncio.sleep(0.1)
|
|
286
|
-
if self.authorization_state == "authorizationStateClosed":
|
|
287
|
-
return
|
|
288
|
-
|
|
289
|
-
if not self.is_running:
|
|
290
|
-
return
|
|
291
|
-
|
|
292
|
-
self.me = await self.getMe()
|
|
293
|
-
if isinstance(self.me, types.Error):
|
|
294
|
-
self.logger.error(f"Get me error: {self.me.message}")
|
|
295
|
-
|
|
296
|
-
self.is_authenticated = True
|
|
297
|
-
|
|
298
|
-
self.logger.info(
|
|
299
|
-
"Logged in as {} {}".format(
|
|
300
|
-
self.me.first_name,
|
|
301
|
-
str(self.me.id)
|
|
302
|
-
if not self.me.usernames
|
|
303
|
-
else "@" + self.me.usernames.editable_username,
|
|
304
|
-
)
|
|
305
|
-
)
|
|
306
|
-
|
|
307
264
|
def add_handler(
|
|
308
265
|
self,
|
|
309
266
|
update_type: str,
|
|
@@ -366,13 +323,11 @@ class Client(Decorators, Methods):
|
|
|
366
323
|
|
|
367
324
|
if not isinstance(func, Callable):
|
|
368
325
|
raise TypeError("func must be callable")
|
|
369
|
-
for
|
|
370
|
-
for handler in
|
|
326
|
+
for _, handlers in self._handlers.items():
|
|
327
|
+
for handler in handlers.copy():
|
|
371
328
|
if handler.func == func:
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
key=lambda x: (x.position is None, x.position)
|
|
375
|
-
)
|
|
329
|
+
handlers.remove(handler)
|
|
330
|
+
handlers.sort(key=lambda x: (x.position is None, x.position))
|
|
376
331
|
return True
|
|
377
332
|
return False
|
|
378
333
|
|
|
@@ -481,7 +436,7 @@ class Client(Decorators, Methods):
|
|
|
481
436
|
|
|
482
437
|
return await self.invoke(kwargs)
|
|
483
438
|
|
|
484
|
-
def run(self
|
|
439
|
+
def run(self) -> None:
|
|
485
440
|
r"""Start the client and block until the client is stopped
|
|
486
441
|
|
|
487
442
|
Example:
|
|
@@ -496,15 +451,11 @@ class Client(Decorators, Methods):
|
|
|
496
451
|
await update.reply_text('Hello!')
|
|
497
452
|
|
|
498
453
|
client.run()
|
|
499
|
-
|
|
500
|
-
Parameters:
|
|
501
|
-
login (``bool``, *optional*):
|
|
502
|
-
Login after start. Default is ``True``
|
|
503
454
|
"""
|
|
504
455
|
|
|
505
456
|
self._register_signal_handlers()
|
|
506
457
|
|
|
507
|
-
self.loop.run_until_complete(self.start(
|
|
458
|
+
self.loop.run_until_complete(self.start())
|
|
508
459
|
self.loop.run_until_complete(self.idle())
|
|
509
460
|
|
|
510
461
|
async def idle(self):
|
|
@@ -549,6 +500,9 @@ class Client(Decorators, Methods):
|
|
|
549
500
|
|
|
550
501
|
self.__stop_client()
|
|
551
502
|
|
|
503
|
+
if not self.client_manager.start_clients_on_add:
|
|
504
|
+
await self.client_manager.close()
|
|
505
|
+
|
|
552
506
|
self.logger.info("Instance closed")
|
|
553
507
|
|
|
554
508
|
return True
|
|
@@ -567,11 +521,7 @@ class Client(Decorators, Methods):
|
|
|
567
521
|
return result
|
|
568
522
|
|
|
569
523
|
async def __send(self, request: dict) -> None:
|
|
570
|
-
if
|
|
571
|
-
self._tdjson.send(
|
|
572
|
-
request
|
|
573
|
-
) # tdjson.send is non-blocking method, So we don't need run_in_executor. This improves performance
|
|
574
|
-
else:
|
|
524
|
+
if self.is_rabbitmq:
|
|
575
525
|
await self.__rchannel.default_exchange.publish(
|
|
576
526
|
aio_pika.Message(
|
|
577
527
|
json_dumps(request, encode=True),
|
|
@@ -579,6 +529,8 @@ class Client(Decorators, Methods):
|
|
|
579
529
|
),
|
|
580
530
|
routing_key=self.__rqueues["requests"].name,
|
|
581
531
|
)
|
|
532
|
+
else:
|
|
533
|
+
self.client_manager.send(self.client_id, request)
|
|
582
534
|
|
|
583
535
|
def _check_init_args(self):
|
|
584
536
|
if self.user_bot:
|
|
@@ -675,31 +627,7 @@ class Client(Decorators, Methods):
|
|
|
675
627
|
self.__cache["is_coro_filter"][func] = is_coro
|
|
676
628
|
return is_coro
|
|
677
629
|
|
|
678
|
-
async def
|
|
679
|
-
if self.is_rabbitmq:
|
|
680
|
-
return
|
|
681
|
-
|
|
682
|
-
with ThreadPoolExecutor(1, "pytdbot_listener") as thread:
|
|
683
|
-
try:
|
|
684
|
-
self.is_running = True
|
|
685
|
-
self.logger.info("Listening to updates...")
|
|
686
|
-
|
|
687
|
-
while self.is_running:
|
|
688
|
-
update = await self.loop.run_in_executor(
|
|
689
|
-
thread,
|
|
690
|
-
self._tdjson.receive,
|
|
691
|
-
1.0, # Seconds
|
|
692
|
-
)
|
|
693
|
-
if update is None:
|
|
694
|
-
continue
|
|
695
|
-
self.loop.create_task(self._process_update(update))
|
|
696
|
-
|
|
697
|
-
except Exception:
|
|
698
|
-
self.logger.exception("Exception in __listen_loop")
|
|
699
|
-
finally:
|
|
700
|
-
self.is_running = False
|
|
701
|
-
|
|
702
|
-
async def _process_update(self, update):
|
|
630
|
+
async def process_update(self, update):
|
|
703
631
|
if not update:
|
|
704
632
|
self.logger.warning("Received None update")
|
|
705
633
|
return
|
|
@@ -891,13 +819,23 @@ class Client(Decorators, Methods):
|
|
|
891
819
|
f"Authorization state changed to {self.authorization_state.removeprefix('authorizationState')}"
|
|
892
820
|
)
|
|
893
821
|
|
|
894
|
-
if self.
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
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
|
+
)
|
|
901
839
|
|
|
902
840
|
if (
|
|
903
841
|
self.authorization_state == "authorizationStateClosed"
|
|
@@ -961,7 +899,7 @@ class Client(Decorators, Methods):
|
|
|
961
899
|
f"Could not connect to TDLib Server after {delay * retries} seconds timeout"
|
|
962
900
|
)
|
|
963
901
|
|
|
964
|
-
async def
|
|
902
|
+
async def __start_rabbitmq(self):
|
|
965
903
|
self.__rconnection = await aio_pika.connect_robust(
|
|
966
904
|
self.__rabbitmq_url,
|
|
967
905
|
client_properties={
|
|
@@ -998,19 +936,7 @@ class Client(Decorators, Methods):
|
|
|
998
936
|
for update in res.updates:
|
|
999
937
|
# when using obj_to_dict the key "@client_id" won't exists
|
|
1000
938
|
# since it's not part of the object
|
|
1001
|
-
await self.
|
|
1002
|
-
|
|
1003
|
-
self.me = await self.getMe()
|
|
1004
|
-
self.is_authenticated = True
|
|
1005
|
-
|
|
1006
|
-
self.logger.info(
|
|
1007
|
-
"Logged in as {} {}".format(
|
|
1008
|
-
self.me.first_name,
|
|
1009
|
-
str(self.me.id)
|
|
1010
|
-
if not self.me.usernames
|
|
1011
|
-
else "@" + self.me.usernames.editable_username,
|
|
1012
|
-
)
|
|
1013
|
-
)
|
|
939
|
+
await self.process_update(obj_to_dict(update))
|
|
1014
940
|
|
|
1015
941
|
if not self.no_updates:
|
|
1016
942
|
await self.__rqueues["updates"].consume(self.__on_update, no_ack=True)
|
|
@@ -1018,20 +944,16 @@ class Client(Decorators, Methods):
|
|
|
1018
944
|
await self.__rqueues["notify"].consume(self.__on_update, no_ack=True)
|
|
1019
945
|
|
|
1020
946
|
async def __handle_rabbitmq_message(self, message: aio_pika.IncomingMessage):
|
|
1021
|
-
await self.
|
|
947
|
+
await self.process_update(json_loads(message.body))
|
|
1022
948
|
|
|
1023
949
|
async def __on_update(self, update):
|
|
1024
950
|
self.loop.create_task(self.__handle_rabbitmq_message(update))
|
|
1025
951
|
|
|
1026
952
|
async def __handle_update_user(self, update: types.UpdateUser):
|
|
1027
|
-
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:
|
|
1028
954
|
self.logger.info(
|
|
1029
|
-
"Updating {}
|
|
1030
|
-
|
|
1031
|
-
str(self.me.id)
|
|
1032
|
-
if not self.me.usernames
|
|
1033
|
-
else "@" + self.me.usernames.editable_username,
|
|
1034
|
-
)
|
|
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"
|
|
1035
957
|
)
|
|
1036
958
|
|
|
1037
959
|
try:
|
|
@@ -1061,28 +983,25 @@ class Client(Decorators, Methods):
|
|
|
1061
983
|
for worker_task in self._workers_tasks:
|
|
1062
984
|
worker_task.cancel()
|
|
1063
985
|
|
|
1064
|
-
if self.__listen_loop_task:
|
|
1065
|
-
self.__listen_loop_task.cancel()
|
|
1066
|
-
|
|
1067
986
|
def _register_signal_handlers(self):
|
|
1068
987
|
def _handle_signal():
|
|
1069
988
|
self.loop.create_task(self.stop())
|
|
1070
|
-
for sig in
|
|
989
|
+
for sig in (
|
|
1071
990
|
signal.SIGINT,
|
|
1072
991
|
signal.SIGTERM,
|
|
1073
992
|
signal.SIGABRT,
|
|
1074
993
|
signal.SIGSEGV,
|
|
1075
|
-
|
|
994
|
+
):
|
|
1076
995
|
self.loop.remove_signal_handler(sig)
|
|
1077
996
|
|
|
1078
997
|
if current_thread() is main_thread():
|
|
1079
998
|
try:
|
|
1080
|
-
for sig in
|
|
999
|
+
for sig in (
|
|
1081
1000
|
signal.SIGINT,
|
|
1082
1001
|
signal.SIGTERM,
|
|
1083
1002
|
signal.SIGABRT,
|
|
1084
1003
|
signal.SIGSEGV,
|
|
1085
|
-
|
|
1004
|
+
):
|
|
1086
1005
|
self.loop.add_signal_handler(sig, _handle_signal)
|
|
1087
1006
|
except NotImplementedError: # Windows dosen't support add_signal_handler
|
|
1088
1007
|
pass
|
|
@@ -1101,12 +1020,12 @@ def deepdiff(self, d1, d2):
|
|
|
1101
1020
|
|
|
1102
1021
|
deep = DeepDiff(d1, d2, ignore_order=True, view="tree")
|
|
1103
1022
|
|
|
1104
|
-
for parent in deep.
|
|
1105
|
-
for diff in
|
|
1023
|
+
for parent, diffs in deep.items():
|
|
1024
|
+
for diff in diffs:
|
|
1106
1025
|
difflist = diff.path(output_format="list")
|
|
1107
|
-
key = ".".join(str
|
|
1026
|
+
key = ".".join(map(str, difflist))
|
|
1108
1027
|
|
|
1109
|
-
if parent in
|
|
1028
|
+
if parent in ("dictionary_item_added", "values_changed"):
|
|
1110
1029
|
self.logger.info(f"{key} changed to {diff.t2}")
|
|
1111
1030
|
elif parent == "dictionary_item_removed":
|
|
1112
1031
|
self.logger.info(f"{key} removed")
|