Pytdbot 0.9.2.dev1__tar.gz → 0.9.2.dev3__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.dev1 → pytdbot-0.9.2.dev3}/PKG-INFO +2 -2
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/Pytdbot.egg-info/PKG-INFO +2 -2
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/Pytdbot.egg-info/SOURCES.txt +2 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/README.md +1 -1
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/__init__.py +11 -2
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/client.py +90 -170
- pytdbot-0.9.2.dev3/pytdbot/client_manager.py +197 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/handlers/td_updates.py +68 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/methods/td_functions.py +550 -72
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/tdjson/tdjson.py +12 -4
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/types/__init__.py +43 -13
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/types/td_types/types.py +898 -84
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/utils/__init__.py +2 -0
- pytdbot-0.9.2.dev3/pytdbot/utils/asyncio_utils.py +10 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/LICENSE +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/MANIFEST.in +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/Pytdbot.egg-info/dependency_links.txt +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/Pytdbot.egg-info/requires.txt +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/Pytdbot.egg-info/top_level.txt +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/exception/__init__.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/filters.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/handlers/__init__.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/handlers/decorators.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/handlers/handler.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/methods/__init__.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/methods/methods.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/tdjson/__init__.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/types/plugins/__init__.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/types/td_types/__init__.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/types/td_types/bound_methods/__init__.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/types/td_types/bound_methods/callback_query.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/types/td_types/bound_methods/chatActions.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/types/td_types/bound_methods/file.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/types/td_types/bound_methods/message.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/utils/escape.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/utils/json_utils.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/utils/obj_encoder.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/utils/strings.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/utils/text_format.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/pytdbot/utils/webapps.py +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/requirements.txt +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/setup.cfg +0 -0
- {pytdbot-0.9.2.dev1 → pytdbot-0.9.2.dev3}/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.dev3
|
|
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.dev3
|
|
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.dev3"
|
|
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
|
|
@@ -802,7 +730,8 @@ class Client(Decorators, Methods):
|
|
|
802
730
|
async def _handle_update(self, update):
|
|
803
731
|
if update.getType() in self._handlers:
|
|
804
732
|
if (
|
|
805
|
-
|
|
733
|
+
not self.user_bot
|
|
734
|
+
and isinstance(update, types.UpdateNewMessage)
|
|
806
735
|
and update.message.is_outgoing
|
|
807
736
|
):
|
|
808
737
|
return
|
|
@@ -890,13 +819,23 @@ class Client(Decorators, Methods):
|
|
|
890
819
|
f"Authorization state changed to {self.authorization_state.removeprefix('authorizationState')}"
|
|
891
820
|
)
|
|
892
821
|
|
|
893
|
-
if self.
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
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
|
+
)
|
|
900
839
|
|
|
901
840
|
if (
|
|
902
841
|
self.authorization_state == "authorizationStateClosed"
|
|
@@ -960,7 +899,7 @@ class Client(Decorators, Methods):
|
|
|
960
899
|
f"Could not connect to TDLib Server after {delay * retries} seconds timeout"
|
|
961
900
|
)
|
|
962
901
|
|
|
963
|
-
async def
|
|
902
|
+
async def __start_rabbitmq(self):
|
|
964
903
|
self.__rconnection = await aio_pika.connect_robust(
|
|
965
904
|
self.__rabbitmq_url,
|
|
966
905
|
client_properties={
|
|
@@ -997,19 +936,7 @@ class Client(Decorators, Methods):
|
|
|
997
936
|
for update in res.updates:
|
|
998
937
|
# when using obj_to_dict the key "@client_id" won't exists
|
|
999
938
|
# since it's not part of the object
|
|
1000
|
-
await self.
|
|
1001
|
-
|
|
1002
|
-
self.me = await self.getMe()
|
|
1003
|
-
self.is_authenticated = True
|
|
1004
|
-
|
|
1005
|
-
self.logger.info(
|
|
1006
|
-
"Logged in as {} {}".format(
|
|
1007
|
-
self.me.first_name,
|
|
1008
|
-
str(self.me.id)
|
|
1009
|
-
if not self.me.usernames
|
|
1010
|
-
else "@" + self.me.usernames.editable_username,
|
|
1011
|
-
)
|
|
1012
|
-
)
|
|
939
|
+
await self.process_update(obj_to_dict(update))
|
|
1013
940
|
|
|
1014
941
|
if not self.no_updates:
|
|
1015
942
|
await self.__rqueues["updates"].consume(self.__on_update, no_ack=True)
|
|
@@ -1017,7 +944,7 @@ class Client(Decorators, Methods):
|
|
|
1017
944
|
await self.__rqueues["notify"].consume(self.__on_update, no_ack=True)
|
|
1018
945
|
|
|
1019
946
|
async def __handle_rabbitmq_message(self, message: aio_pika.IncomingMessage):
|
|
1020
|
-
await self.
|
|
947
|
+
await self.process_update(json_loads(message.body))
|
|
1021
948
|
|
|
1022
949
|
async def __on_update(self, update):
|
|
1023
950
|
self.loop.create_task(self.__handle_rabbitmq_message(update))
|
|
@@ -1025,12 +952,8 @@ class Client(Decorators, Methods):
|
|
|
1025
952
|
async def __handle_update_user(self, update: types.UpdateUser):
|
|
1026
953
|
if self.is_authenticated and update.user.id == self.me.id:
|
|
1027
954
|
self.logger.info(
|
|
1028
|
-
"Updating {}
|
|
1029
|
-
|
|
1030
|
-
str(self.me.id)
|
|
1031
|
-
if not self.me.usernames
|
|
1032
|
-
else "@" + self.me.usernames.editable_username,
|
|
1033
|
-
)
|
|
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"
|
|
1034
957
|
)
|
|
1035
958
|
|
|
1036
959
|
try:
|
|
@@ -1060,28 +983,25 @@ class Client(Decorators, Methods):
|
|
|
1060
983
|
for worker_task in self._workers_tasks:
|
|
1061
984
|
worker_task.cancel()
|
|
1062
985
|
|
|
1063
|
-
if self.__listen_loop_task:
|
|
1064
|
-
self.__listen_loop_task.cancel()
|
|
1065
|
-
|
|
1066
986
|
def _register_signal_handlers(self):
|
|
1067
987
|
def _handle_signal():
|
|
1068
988
|
self.loop.create_task(self.stop())
|
|
1069
|
-
for sig in
|
|
989
|
+
for sig in (
|
|
1070
990
|
signal.SIGINT,
|
|
1071
991
|
signal.SIGTERM,
|
|
1072
992
|
signal.SIGABRT,
|
|
1073
993
|
signal.SIGSEGV,
|
|
1074
|
-
|
|
994
|
+
):
|
|
1075
995
|
self.loop.remove_signal_handler(sig)
|
|
1076
996
|
|
|
1077
997
|
if current_thread() is main_thread():
|
|
1078
998
|
try:
|
|
1079
|
-
for sig in
|
|
999
|
+
for sig in (
|
|
1080
1000
|
signal.SIGINT,
|
|
1081
1001
|
signal.SIGTERM,
|
|
1082
1002
|
signal.SIGABRT,
|
|
1083
1003
|
signal.SIGSEGV,
|
|
1084
|
-
|
|
1004
|
+
):
|
|
1085
1005
|
self.loop.add_signal_handler(sig, _handle_signal)
|
|
1086
1006
|
except NotImplementedError: # Windows dosen't support add_signal_handler
|
|
1087
1007
|
pass
|
|
@@ -1100,12 +1020,12 @@ def deepdiff(self, d1, d2):
|
|
|
1100
1020
|
|
|
1101
1021
|
deep = DeepDiff(d1, d2, ignore_order=True, view="tree")
|
|
1102
1022
|
|
|
1103
|
-
for parent in deep.
|
|
1104
|
-
for diff in
|
|
1023
|
+
for parent, diffs in deep.items():
|
|
1024
|
+
for diff in diffs:
|
|
1105
1025
|
difflist = diff.path(output_format="list")
|
|
1106
|
-
key = ".".join(str
|
|
1026
|
+
key = ".".join(map(str, difflist))
|
|
1107
1027
|
|
|
1108
|
-
if parent in
|
|
1028
|
+
if parent in ("dictionary_item_added", "values_changed"):
|
|
1109
1029
|
self.logger.info(f"{key} changed to {diff.t2}")
|
|
1110
1030
|
elif parent == "dictionary_item_removed":
|
|
1111
1031
|
self.logger.info(f"{key} removed")
|