Pytdbot 0.10.0.dev3__tar.gz → 0.10.0.dev5__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.10.0.dev3 → pytdbot-0.10.0.dev5}/PKG-INFO +3 -3
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/Pytdbot.egg-info/PKG-INFO +3 -3
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/Pytdbot.egg-info/requires.txt +3 -1
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/README.md +0 -1
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pyproject.toml +2 -1
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/__init__.py +1 -1
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/client.py +101 -137
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/LICENSE +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/MANIFEST.in +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/Pytdbot.egg-info/SOURCES.txt +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/Pytdbot.egg-info/dependency_links.txt +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/Pytdbot.egg-info/top_level.txt +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/client_manager.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/exception/__init__.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/filters.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/handlers/__init__.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/handlers/decorators.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/handlers/handler.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/handlers/td_updates.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/methods/__init__.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/methods/methods.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/methods/td_functions.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/tdjson/__init__.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/tdjson/tdjson.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/types/__init__.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/types/bound_methods/__init__.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/types/bound_methods/callback_query.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/types/bound_methods/chatActions.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/types/bound_methods/file.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/types/bound_methods/message.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/types/bound_methods/sender_id.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/types/plugins/__init__.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/types/td_types.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/types/tdserver/__init__.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/types/tdserver/schedule.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/types/tdserver/stats.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/utils/__init__.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/utils/albums.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/utils/escape.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/utils/json_utils.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/utils/obj_encoder.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/utils/strings.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/utils/text_format.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/pytdbot/utils/webapps.py +0 -0
- {pytdbot-0.10.0.dev3 → pytdbot-0.10.0.dev5}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Pytdbot
|
|
3
|
-
Version: 0.10.0.
|
|
3
|
+
Version: 0.10.0.dev5
|
|
4
4
|
Summary: Easy-to-use asynchronous TDLib wrapper for Python.
|
|
5
5
|
Author-email: AYMEN A <let.me.code.safe@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,9 +23,10 @@ Requires-Python: >=3.10
|
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
25
|
Requires-Dist: deepdiff
|
|
26
|
-
Requires-Dist: aio_pika
|
|
27
26
|
Provides-Extra: tdjson
|
|
28
27
|
Requires-Dist: tdjson; extra == "tdjson"
|
|
28
|
+
Provides-Extra: nats
|
|
29
|
+
Requires-Dist: nats-py; extra == "nats"
|
|
29
30
|
Dynamic: license-file
|
|
30
31
|
|
|
31
32
|
# Pytdbot
|
|
@@ -60,7 +61,6 @@ Pytdbot is an asynchronous [**TDLib**](https://github.com/tdlib/td) wrapper for
|
|
|
60
61
|
- Telegram [API key](https://my.telegram.org/apps)
|
|
61
62
|
- [tdjson](https://github.com/AYMENJD/tdjson) or [TDLib](https://github.com/tdlib/td#building)
|
|
62
63
|
- [deepdiff](https://github.com/seperman/deepdiff)
|
|
63
|
-
- [aio-pika](https://github.com/mosquito/aio-pika)
|
|
64
64
|
|
|
65
65
|
### Installation
|
|
66
66
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Pytdbot
|
|
3
|
-
Version: 0.10.0.
|
|
3
|
+
Version: 0.10.0.dev5
|
|
4
4
|
Summary: Easy-to-use asynchronous TDLib wrapper for Python.
|
|
5
5
|
Author-email: AYMEN A <let.me.code.safe@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,9 +23,10 @@ Requires-Python: >=3.10
|
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
25
|
Requires-Dist: deepdiff
|
|
26
|
-
Requires-Dist: aio_pika
|
|
27
26
|
Provides-Extra: tdjson
|
|
28
27
|
Requires-Dist: tdjson; extra == "tdjson"
|
|
28
|
+
Provides-Extra: nats
|
|
29
|
+
Requires-Dist: nats-py; extra == "nats"
|
|
29
30
|
Dynamic: license-file
|
|
30
31
|
|
|
31
32
|
# Pytdbot
|
|
@@ -60,7 +61,6 @@ Pytdbot is an asynchronous [**TDLib**](https://github.com/tdlib/td) wrapper for
|
|
|
60
61
|
- Telegram [API key](https://my.telegram.org/apps)
|
|
61
62
|
- [tdjson](https://github.com/AYMENJD/tdjson) or [TDLib](https://github.com/tdlib/td#building)
|
|
62
63
|
- [deepdiff](https://github.com/seperman/deepdiff)
|
|
63
|
-
- [aio-pika](https://github.com/mosquito/aio-pika)
|
|
64
64
|
|
|
65
65
|
### Installation
|
|
66
66
|
|
|
@@ -30,7 +30,6 @@ Pytdbot is an asynchronous [**TDLib**](https://github.com/tdlib/td) wrapper for
|
|
|
30
30
|
- Telegram [API key](https://my.telegram.org/apps)
|
|
31
31
|
- [tdjson](https://github.com/AYMENJD/tdjson) or [TDLib](https://github.com/tdlib/td#building)
|
|
32
32
|
- [deepdiff](https://github.com/seperman/deepdiff)
|
|
33
|
-
- [aio-pika](https://github.com/mosquito/aio-pika)
|
|
34
33
|
|
|
35
34
|
### Installation
|
|
36
35
|
|
|
@@ -11,7 +11,7 @@ requires-python = ">=3.10"
|
|
|
11
11
|
license = "MIT"
|
|
12
12
|
license-files = ["LICENSE"]
|
|
13
13
|
authors = [{ name = "AYMEN A", email = "let.me.code.safe@gmail.com" }]
|
|
14
|
-
dependencies = ["deepdiff"
|
|
14
|
+
dependencies = ["deepdiff"]
|
|
15
15
|
keywords = [
|
|
16
16
|
"telegram",
|
|
17
17
|
"tdlib",
|
|
@@ -43,6 +43,7 @@ Tracker = "https://github.com/pytdbot/client/issues"
|
|
|
43
43
|
|
|
44
44
|
[project.optional-dependencies]
|
|
45
45
|
tdjson = ["tdjson"]
|
|
46
|
+
nats = ["nats-py"]
|
|
46
47
|
|
|
47
48
|
[tool.setuptools.packages.find]
|
|
48
49
|
exclude = ["examples"]
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import signal
|
|
5
|
+
import sys
|
|
5
6
|
from collections.abc import Callable
|
|
6
7
|
from importlib import import_module
|
|
7
8
|
from importlib import reload as reload_module
|
|
@@ -13,7 +14,11 @@ from pathlib import Path
|
|
|
13
14
|
from platform import python_implementation, python_version
|
|
14
15
|
from threading import current_thread, main_thread
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
try:
|
|
18
|
+
import nats
|
|
19
|
+
except ImportError:
|
|
20
|
+
nats = None
|
|
21
|
+
|
|
17
22
|
from deepdiff import DeepDiff
|
|
18
23
|
|
|
19
24
|
import pytdbot
|
|
@@ -48,11 +53,11 @@ class Client(Decorators, Methods):
|
|
|
48
53
|
api_hash (``str``, *optional*):
|
|
49
54
|
Identifier hash for Telegram API access, which can be obtained at https://my.telegram.org
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
URL for
|
|
56
|
+
nats_url (``str``, *optional*):
|
|
57
|
+
URL for NATS server connection
|
|
53
58
|
|
|
54
59
|
instance_id (``str``, *optional*):
|
|
55
|
-
Instance ID for
|
|
60
|
+
Instance ID for NATS connections and queues. Default is ``None`` (random)
|
|
56
61
|
|
|
57
62
|
lib_path (``str``, *optional*):
|
|
58
63
|
Path to TDLib library. Default is ``None`` (auto-detect)
|
|
@@ -115,7 +120,7 @@ class Client(Decorators, Methods):
|
|
|
115
120
|
token: str | None = None,
|
|
116
121
|
api_id: int | None = None,
|
|
117
122
|
api_hash: str | None = None,
|
|
118
|
-
|
|
123
|
+
nats_url: str | None = None,
|
|
119
124
|
instance_id: str | None = None,
|
|
120
125
|
lib_path: str | None = None,
|
|
121
126
|
plugins: Plugins | None = None,
|
|
@@ -137,12 +142,11 @@ class Client(Decorators, Methods):
|
|
|
137
142
|
td_verbosity: int = 2,
|
|
138
143
|
td_log: LogStream | None = None,
|
|
139
144
|
user_bot: bool = False,
|
|
140
|
-
server_ack: bool = True,
|
|
141
145
|
) -> None:
|
|
142
146
|
self.__api_id = api_id
|
|
143
147
|
self.__api_hash = api_hash
|
|
144
|
-
self.
|
|
145
|
-
self.
|
|
148
|
+
self.__nats_url = nats_url
|
|
149
|
+
self._nats_instance_id = (
|
|
146
150
|
instance_id if isinstance(instance_id, str) else create_extra_id(4)
|
|
147
151
|
)
|
|
148
152
|
self.__token = token
|
|
@@ -170,7 +174,6 @@ class Client(Decorators, Methods):
|
|
|
170
174
|
self.load_messages_before_reply = load_messages_before_reply
|
|
171
175
|
self.queue = asyncio.Queue()
|
|
172
176
|
self.user_bot = user_bot
|
|
173
|
-
self.server_ack = server_ack
|
|
174
177
|
self.my_id = (
|
|
175
178
|
get_bot_id_from_token(self.__token)
|
|
176
179
|
if isinstance(self.__token, str)
|
|
@@ -186,7 +189,7 @@ class Client(Decorators, Methods):
|
|
|
186
189
|
self.me: types.User = None
|
|
187
190
|
self.is_authenticated = False
|
|
188
191
|
self.is_reloading_plugins = False
|
|
189
|
-
self.
|
|
192
|
+
self.is_nats = True if nats_url else False
|
|
190
193
|
self.options = {}
|
|
191
194
|
self.allow_outgoing_message_types: tuple = (types.MessagePaymentRefunded,)
|
|
192
195
|
self.get_message_methods = {
|
|
@@ -203,7 +206,6 @@ class Client(Decorators, Methods):
|
|
|
203
206
|
self._results: dict[str, asyncio.Future] = {}
|
|
204
207
|
self._workers_tasks = None
|
|
205
208
|
self.__wait_login: asyncio.Event = None
|
|
206
|
-
self.__rabbitmq_iterator_task = None
|
|
207
209
|
self.__authorization_state: str = None
|
|
208
210
|
self.__cache = {"is_coro_filter": {}}
|
|
209
211
|
self.__local_handlers = {
|
|
@@ -219,10 +221,11 @@ class Client(Decorators, Methods):
|
|
|
219
221
|
self.__idle_event: asyncio.Event = None
|
|
220
222
|
self.__closed_event: asyncio.Event = None
|
|
221
223
|
|
|
222
|
-
#
|
|
223
|
-
self.
|
|
224
|
-
self.
|
|
225
|
-
self.
|
|
224
|
+
# NATS
|
|
225
|
+
self.__nc = None
|
|
226
|
+
self.__requests_subject = f"bot.{self.my_id}.requests"
|
|
227
|
+
self.__updates_subject = f"bot.{self.my_id}.updates"
|
|
228
|
+
self.__broadcast_subject = f"bot.{self.my_id}.broadcast"
|
|
226
229
|
|
|
227
230
|
self.loop = None
|
|
228
231
|
|
|
@@ -252,7 +255,7 @@ class Client(Decorators, Methods):
|
|
|
252
255
|
) -> pytdbot.types.ServerStats | pytdbot.types.Error:
|
|
253
256
|
"""Returns TDLib Server stats"""
|
|
254
257
|
|
|
255
|
-
self.
|
|
258
|
+
self._check_nats()
|
|
256
259
|
|
|
257
260
|
return await self.invoke({"@type": "getServerStats"})
|
|
258
261
|
|
|
@@ -272,7 +275,7 @@ class Client(Decorators, Methods):
|
|
|
272
275
|
Unix timestamp when the event should be sent
|
|
273
276
|
"""
|
|
274
277
|
|
|
275
|
-
self.
|
|
278
|
+
self._check_nats()
|
|
276
279
|
|
|
277
280
|
if not isinstance(name, str):
|
|
278
281
|
raise ValueError("name must be str")
|
|
@@ -300,7 +303,7 @@ class Client(Decorators, Methods):
|
|
|
300
303
|
Event ID to cancel
|
|
301
304
|
"""
|
|
302
305
|
|
|
303
|
-
self.
|
|
306
|
+
self._check_nats()
|
|
304
307
|
|
|
305
308
|
if not isinstance(event_id, str):
|
|
306
309
|
raise ValueError("event_id must be str")
|
|
@@ -324,8 +327,8 @@ class Client(Decorators, Methods):
|
|
|
324
327
|
self.__idle_event = asyncio.Event()
|
|
325
328
|
self.__closed_event = asyncio.Event()
|
|
326
329
|
|
|
327
|
-
if self.
|
|
328
|
-
await self.
|
|
330
|
+
if self.is_nats:
|
|
331
|
+
await self.__start_nats()
|
|
329
332
|
elif not self.client_manager:
|
|
330
333
|
self.__wait_login = asyncio.Event() if not self.user_bot else None
|
|
331
334
|
|
|
@@ -335,25 +338,19 @@ class Client(Decorators, Methods):
|
|
|
335
338
|
await self.client_manager.start()
|
|
336
339
|
self.is_running = True
|
|
337
340
|
|
|
338
|
-
if isinstance(self.td_log, LogStream) and not self.
|
|
341
|
+
if isinstance(self.td_log, LogStream) and not self.is_nats:
|
|
339
342
|
await self.__send(
|
|
340
343
|
{"@type": "setLogStream", "log_stream": obj_to_dict(self.td_log)}
|
|
341
344
|
)
|
|
342
345
|
|
|
343
|
-
if isinstance(self.workers, int):
|
|
346
|
+
if isinstance(self.workers, int) and not self.is_nats:
|
|
344
347
|
self._workers_tasks = [
|
|
345
|
-
self.loop.create_task(
|
|
346
|
-
self._queue_update_worker()
|
|
347
|
-
if not self.is_rabbitmq
|
|
348
|
-
else self.__rabbitmq_worker()
|
|
349
|
-
)
|
|
348
|
+
self.loop.create_task(self._queue_update_worker())
|
|
350
349
|
for _ in range(self.workers)
|
|
351
350
|
]
|
|
352
351
|
self.__is_queue_worker = True
|
|
353
352
|
|
|
354
353
|
self.logger.info(f"Started with {self.workers} workers")
|
|
355
|
-
elif self.is_rabbitmq:
|
|
356
|
-
raise ValueError("workers must be an int when using TDLib Server")
|
|
357
354
|
else:
|
|
358
355
|
self.__is_queue_worker = False
|
|
359
356
|
self.logger.info("Started with unlimited updates processes")
|
|
@@ -670,11 +667,27 @@ class Client(Decorators, Methods):
|
|
|
670
667
|
}:
|
|
671
668
|
await self.close()
|
|
672
669
|
|
|
670
|
+
if self.is_nats:
|
|
671
|
+
# fake closing because TDLib Server doesn't allow close() from workers
|
|
672
|
+
await self.process_update(
|
|
673
|
+
obj_to_dict(
|
|
674
|
+
types.UpdateAuthorizationState(
|
|
675
|
+
authorization_state=types.AuthorizationStateClosing()
|
|
676
|
+
)
|
|
677
|
+
)
|
|
678
|
+
)
|
|
679
|
+
await self.process_update(
|
|
680
|
+
obj_to_dict(
|
|
681
|
+
types.UpdateAuthorizationState(
|
|
682
|
+
authorization_state=types.AuthorizationStateClosed()
|
|
683
|
+
)
|
|
684
|
+
)
|
|
685
|
+
)
|
|
686
|
+
|
|
673
687
|
await self.__closed_event.wait()
|
|
674
688
|
|
|
675
|
-
if self.
|
|
676
|
-
await self.
|
|
677
|
-
await self.__rconnection.close()
|
|
689
|
+
if self.is_nats:
|
|
690
|
+
await self.__nc.close()
|
|
678
691
|
|
|
679
692
|
self.__stop_client()
|
|
680
693
|
|
|
@@ -700,25 +713,25 @@ class Client(Decorators, Methods):
|
|
|
700
713
|
return result
|
|
701
714
|
|
|
702
715
|
async def __send(self, request: dict) -> None:
|
|
703
|
-
if self.
|
|
704
|
-
await self.
|
|
705
|
-
|
|
716
|
+
if self.is_nats:
|
|
717
|
+
await self.__on_update(
|
|
718
|
+
await self.__nc.request(
|
|
719
|
+
self.__requests_subject,
|
|
706
720
|
json_dumps(request, encode=True),
|
|
707
|
-
|
|
708
|
-
)
|
|
709
|
-
routing_key=self.__rqueues["requests"].name,
|
|
721
|
+
timeout=None,
|
|
722
|
+
)
|
|
710
723
|
)
|
|
711
724
|
else:
|
|
712
725
|
self.client_manager.send(self.client_id, request)
|
|
713
726
|
|
|
714
|
-
def
|
|
715
|
-
assert self.
|
|
727
|
+
def _check_nats(self):
|
|
728
|
+
assert self.is_nats, "This method is only available for TDLib Server"
|
|
716
729
|
|
|
717
730
|
def _check_init_args(self):
|
|
718
731
|
if self.user_bot:
|
|
719
732
|
return
|
|
720
733
|
|
|
721
|
-
if not self.
|
|
734
|
+
if not self.is_nats:
|
|
722
735
|
if not isinstance(self.__api_id, int):
|
|
723
736
|
raise TypeError("api_id must be an int")
|
|
724
737
|
if not isinstance(self.__api_hash, str):
|
|
@@ -849,7 +862,7 @@ class Client(Decorators, Methods):
|
|
|
849
862
|
if handler := self.__local_handlers.get(update.get("@type")):
|
|
850
863
|
self.loop.create_task(handler(update_obj))
|
|
851
864
|
|
|
852
|
-
if not self.
|
|
865
|
+
if not self.is_nats and self.__is_queue_worker:
|
|
853
866
|
self.queue.put_nowait(update_obj)
|
|
854
867
|
else:
|
|
855
868
|
await self._handle_update(update_obj)
|
|
@@ -997,7 +1010,7 @@ class Client(Decorators, Methods):
|
|
|
997
1010
|
`AuthorizationError`
|
|
998
1011
|
"""
|
|
999
1012
|
|
|
1000
|
-
if self.
|
|
1013
|
+
if self.is_nats:
|
|
1001
1014
|
return
|
|
1002
1015
|
|
|
1003
1016
|
if isinstance(self.__database_encryption_key, str):
|
|
@@ -1041,13 +1054,15 @@ class Client(Decorators, Methods):
|
|
|
1041
1054
|
else:
|
|
1042
1055
|
raise ValueError(f"Option {k} has unsupported type {v_type}")
|
|
1043
1056
|
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1057
|
+
self.loop.create_task(
|
|
1058
|
+
self.__send(
|
|
1059
|
+
{
|
|
1060
|
+
"@type": "setOption",
|
|
1061
|
+
"name": k,
|
|
1062
|
+
"value": data,
|
|
1063
|
+
"@extra": {"option": k, "value": v, "id": ""},
|
|
1064
|
+
}
|
|
1065
|
+
)
|
|
1051
1066
|
)
|
|
1052
1067
|
self.logger.debug(f"Option {k} sent with value {v}")
|
|
1053
1068
|
|
|
@@ -1068,6 +1083,7 @@ class Client(Decorators, Methods):
|
|
|
1068
1083
|
await self.__handle_authorization_state_wait_phone_number()
|
|
1069
1084
|
elif self.authorization_state == "authorizationStateReady":
|
|
1070
1085
|
self.is_authenticated = True
|
|
1086
|
+
self.__idle_event.clear()
|
|
1071
1087
|
|
|
1072
1088
|
self.me = await self.getMe()
|
|
1073
1089
|
if isinstance(self.me, types.Error):
|
|
@@ -1130,56 +1146,49 @@ class Client(Decorators, Methods):
|
|
|
1130
1146
|
f"Option {update.name} changed to {self.options[update.name]}"
|
|
1131
1147
|
)
|
|
1132
1148
|
|
|
1133
|
-
async def
|
|
1134
|
-
|
|
1135
|
-
try:
|
|
1136
|
-
return await self.__rchannel.get_queue(self.my_id + "_updates")
|
|
1137
|
-
except aio_pika.exceptions.ChannelNotFoundEntity:
|
|
1138
|
-
self.logger.warning(
|
|
1139
|
-
f"Attempt {attempt + 1}: TDLib Server is not running. Retrying in {delay} seconds..."
|
|
1140
|
-
)
|
|
1141
|
-
await asyncio.sleep(delay)
|
|
1142
|
-
self.logger.error(
|
|
1143
|
-
f"Could not connect to TDLib Server after {retries} attempts."
|
|
1144
|
-
)
|
|
1145
|
-
raise AuthorizationError(
|
|
1146
|
-
f"Could not connect to TDLib Server after {delay * retries} seconds timeout"
|
|
1147
|
-
)
|
|
1149
|
+
async def __nc_error_handler(self, e):
|
|
1150
|
+
self.logger.error(f"NATS connection error: {e}")
|
|
1148
1151
|
|
|
1149
|
-
async def
|
|
1150
|
-
self.
|
|
1151
|
-
self.__rabbitmq_url,
|
|
1152
|
-
client_properties={
|
|
1153
|
-
"connection_name": f"Pytdbot instance {self._rabbitmq_instance_id}"
|
|
1154
|
-
},
|
|
1155
|
-
)
|
|
1156
|
-
self.__rchannel = await self.__rconnection.channel()
|
|
1152
|
+
async def __nc_reconnect_handler(self):
|
|
1153
|
+
self.logger.info("Reconnected to NATS server")
|
|
1157
1154
|
|
|
1158
|
-
|
|
1155
|
+
async def __nc_disconnect_handler(self):
|
|
1156
|
+
self.logger.info("Disconnected from NATS server")
|
|
1159
1157
|
|
|
1160
|
-
|
|
1158
|
+
async def __nc_closed_handler(self):
|
|
1159
|
+
self.logger.info("Closed connection to NATS server")
|
|
1161
1160
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
)
|
|
1161
|
+
async def __start_nats(self):
|
|
1162
|
+
if not nats:
|
|
1163
|
+
raise ImportError(
|
|
1164
|
+
f"nats-py is not installed, please install it with `{sys.executable} -m pip install --upgrade nats-py`"
|
|
1165
|
+
)
|
|
1168
1166
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1167
|
+
self.__nc = await nats.connect(
|
|
1168
|
+
self.__nats_url,
|
|
1169
|
+
name=f"Pytdbot instance {self._nats_instance_id}",
|
|
1170
|
+
error_cb=self.__nc_error_handler,
|
|
1171
|
+
reconnected_cb=self.__nc_reconnect_handler,
|
|
1172
|
+
closed_cb=self.__nc_closed_handler,
|
|
1173
|
+
disconnected_cb=self.__nc_disconnect_handler,
|
|
1174
|
+
max_reconnect_attempts=-1,
|
|
1171
1175
|
)
|
|
1172
1176
|
|
|
1173
|
-
self.
|
|
1174
|
-
"
|
|
1175
|
-
|
|
1176
|
-
"
|
|
1177
|
-
"responses": responses_queue,
|
|
1178
|
-
}
|
|
1177
|
+
if self.__nc.is_connected:
|
|
1178
|
+
self.logger.info("Connected to TDLib server via NATS")
|
|
1179
|
+
else:
|
|
1180
|
+
raise AuthorizationError("Failed to connect to TDLib server via NATS")
|
|
1179
1181
|
|
|
1180
1182
|
self.is_running = True
|
|
1181
1183
|
|
|
1182
|
-
|
|
1184
|
+
if not self.no_updates:
|
|
1185
|
+
await self.__nc.subscribe(
|
|
1186
|
+
self.__updates_subject,
|
|
1187
|
+
queue="updates",
|
|
1188
|
+
cb=self.__on_update,
|
|
1189
|
+
)
|
|
1190
|
+
|
|
1191
|
+
await self.__nc.subscribe(self.__broadcast_subject, cb=self.__on_update)
|
|
1183
1192
|
|
|
1184
1193
|
await self._set_options()
|
|
1185
1194
|
|
|
@@ -1189,50 +1198,8 @@ class Client(Decorators, Methods):
|
|
|
1189
1198
|
# since it's not part of the object
|
|
1190
1199
|
await self.process_update(obj_to_dict(update))
|
|
1191
1200
|
|
|
1192
|
-
if not self.no_updates:
|
|
1193
|
-
self.__rabbitmq_iterator_task = self.loop.create_task(
|
|
1194
|
-
self.__rabbitmq_iterator()
|
|
1195
|
-
)
|
|
1196
|
-
|
|
1197
|
-
await self.__rqueues["notify"].consume(self.__on_update, no_ack=True)
|
|
1198
|
-
|
|
1199
|
-
async def __rabbitmq_iterator(self):
|
|
1200
|
-
async with self.__rqueues["updates"].iterator(
|
|
1201
|
-
no_ack=not self.server_ack
|
|
1202
|
-
) as iterator:
|
|
1203
|
-
async for message in iterator:
|
|
1204
|
-
if self.queue.qsize() > self.queue_size:
|
|
1205
|
-
await message.nack(requeue=True)
|
|
1206
|
-
continue
|
|
1207
|
-
|
|
1208
|
-
self.queue.put_nowait(message)
|
|
1209
|
-
|
|
1210
|
-
async def __rabbitmq_worker(self):
|
|
1211
|
-
while self.is_running:
|
|
1212
|
-
try:
|
|
1213
|
-
message: aio_pika.IncomingMessage = self.queue.get_nowait()
|
|
1214
|
-
except asyncio.QueueEmpty:
|
|
1215
|
-
message: aio_pika.IncomingMessage = await self.queue.get()
|
|
1216
|
-
|
|
1217
|
-
try:
|
|
1218
|
-
update = json_loads(message.body)
|
|
1219
|
-
if self.__is_closing and not isinstance(
|
|
1220
|
-
update, types.UpdateAuthorizationState
|
|
1221
|
-
):
|
|
1222
|
-
await message.nack(requeue=True)
|
|
1223
|
-
continue
|
|
1224
|
-
|
|
1225
|
-
await self.process_update(update)
|
|
1226
|
-
except Exception:
|
|
1227
|
-
self.logger.exception("Error processing message")
|
|
1228
|
-
|
|
1229
|
-
await message.ack() # ack after processing
|
|
1230
|
-
|
|
1231
|
-
async def __handle_rabbitmq_message(self, message: aio_pika.IncomingMessage):
|
|
1232
|
-
await self.process_update(json_loads(message.body))
|
|
1233
|
-
|
|
1234
1201
|
async def __on_update(self, update):
|
|
1235
|
-
self.loop.create_task(self.
|
|
1202
|
+
self.loop.create_task(self.process_update(json_loads(update.data)))
|
|
1236
1203
|
|
|
1237
1204
|
async def __handle_update_user(self, update: types.UpdateUser):
|
|
1238
1205
|
if self.is_authenticated and self.me and update.user.id == self.me.id:
|
|
@@ -1249,7 +1216,7 @@ class Client(Decorators, Methods):
|
|
|
1249
1216
|
|
|
1250
1217
|
async def __handle_authorization_state_wait_phone_number(self):
|
|
1251
1218
|
if (
|
|
1252
|
-
self.
|
|
1219
|
+
self.is_nats
|
|
1253
1220
|
or self.authorization_state != "authorizationStateWaitPhoneNumber"
|
|
1254
1221
|
or not self.__token
|
|
1255
1222
|
):
|
|
@@ -1265,9 +1232,6 @@ class Client(Decorators, Methods):
|
|
|
1265
1232
|
self.is_authenticated = False
|
|
1266
1233
|
self.is_running = False
|
|
1267
1234
|
|
|
1268
|
-
if self.__rabbitmq_iterator_task:
|
|
1269
|
-
self.__rabbitmq_iterator_task.cancel()
|
|
1270
|
-
|
|
1271
1235
|
if self.__is_queue_worker:
|
|
1272
1236
|
for worker_task in self._workers_tasks:
|
|
1273
1237
|
worker_task.cancel()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|