telegrinder 0.4.2__py3-none-any.whl → 0.5.1__py3-none-any.whl
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.
Potentially problematic release.
This version of telegrinder might be problematic. Click here for more details.
- telegrinder/__init__.py +37 -55
- telegrinder/__meta__.py +1 -0
- telegrinder/api/__init__.py +6 -4
- telegrinder/api/api.py +100 -26
- telegrinder/api/error.py +42 -8
- telegrinder/api/response.py +4 -1
- telegrinder/api/token.py +2 -2
- telegrinder/bot/__init__.py +9 -25
- telegrinder/bot/bot.py +31 -25
- telegrinder/bot/cute_types/__init__.py +0 -0
- telegrinder/bot/cute_types/base.py +103 -61
- telegrinder/bot/cute_types/callback_query.py +447 -400
- telegrinder/bot/cute_types/chat_join_request.py +59 -62
- telegrinder/bot/cute_types/chat_member_updated.py +154 -157
- telegrinder/bot/cute_types/inline_query.py +41 -44
- telegrinder/bot/cute_types/message.py +98 -67
- telegrinder/bot/cute_types/pre_checkout_query.py +38 -42
- telegrinder/bot/cute_types/update.py +1 -8
- telegrinder/bot/cute_types/utils.py +1 -1
- telegrinder/bot/dispatch/__init__.py +10 -15
- telegrinder/bot/dispatch/abc.py +12 -11
- telegrinder/bot/dispatch/action.py +104 -0
- telegrinder/bot/dispatch/context.py +32 -26
- telegrinder/bot/dispatch/dispatch.py +61 -134
- telegrinder/bot/dispatch/handler/__init__.py +2 -0
- telegrinder/bot/dispatch/handler/abc.py +10 -8
- telegrinder/bot/dispatch/handler/audio_reply.py +2 -3
- telegrinder/bot/dispatch/handler/base.py +10 -33
- telegrinder/bot/dispatch/handler/document_reply.py +2 -3
- telegrinder/bot/dispatch/handler/func.py +55 -87
- telegrinder/bot/dispatch/handler/media_group_reply.py +2 -3
- telegrinder/bot/dispatch/handler/message_reply.py +2 -3
- telegrinder/bot/dispatch/handler/photo_reply.py +2 -3
- telegrinder/bot/dispatch/handler/sticker_reply.py +2 -3
- telegrinder/bot/dispatch/handler/video_reply.py +2 -3
- telegrinder/bot/dispatch/middleware/__init__.py +0 -0
- telegrinder/bot/dispatch/middleware/abc.py +79 -55
- telegrinder/bot/dispatch/middleware/global_middleware.py +18 -33
- telegrinder/bot/dispatch/process.py +84 -105
- telegrinder/bot/dispatch/return_manager/__init__.py +0 -0
- telegrinder/bot/dispatch/return_manager/abc.py +102 -65
- telegrinder/bot/dispatch/return_manager/callback_query.py +4 -5
- telegrinder/bot/dispatch/return_manager/inline_query.py +3 -4
- telegrinder/bot/dispatch/return_manager/message.py +8 -10
- telegrinder/bot/dispatch/return_manager/pre_checkout_query.py +4 -5
- telegrinder/bot/dispatch/view/__init__.py +4 -4
- telegrinder/bot/dispatch/view/abc.py +6 -16
- telegrinder/bot/dispatch/view/base.py +54 -178
- telegrinder/bot/dispatch/view/box.py +19 -18
- telegrinder/bot/dispatch/view/callback_query.py +4 -8
- telegrinder/bot/dispatch/view/chat_join_request.py +5 -6
- telegrinder/bot/dispatch/view/chat_member.py +5 -25
- telegrinder/bot/dispatch/view/error.py +9 -0
- telegrinder/bot/dispatch/view/inline_query.py +4 -8
- telegrinder/bot/dispatch/view/message.py +5 -25
- telegrinder/bot/dispatch/view/pre_checkout_query.py +4 -8
- telegrinder/bot/dispatch/view/raw.py +3 -109
- telegrinder/bot/dispatch/waiter_machine/__init__.py +2 -5
- telegrinder/bot/dispatch/waiter_machine/actions.py +6 -4
- telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +1 -3
- telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +1 -1
- telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +11 -7
- telegrinder/bot/dispatch/waiter_machine/hasher/message.py +0 -0
- telegrinder/bot/dispatch/waiter_machine/machine.py +43 -60
- telegrinder/bot/dispatch/waiter_machine/middleware.py +19 -23
- telegrinder/bot/dispatch/waiter_machine/short_state.py +6 -5
- telegrinder/bot/polling/__init__.py +0 -0
- telegrinder/bot/polling/abc.py +0 -0
- telegrinder/bot/polling/polling.py +209 -88
- telegrinder/bot/rules/__init__.py +3 -16
- telegrinder/bot/rules/abc.py +42 -122
- telegrinder/bot/rules/callback_data.py +29 -49
- telegrinder/bot/rules/chat_join.py +5 -23
- telegrinder/bot/rules/command.py +8 -4
- telegrinder/bot/rules/enum_text.py +3 -4
- telegrinder/bot/rules/func.py +7 -14
- telegrinder/bot/rules/fuzzy.py +3 -4
- telegrinder/bot/rules/inline.py +8 -20
- telegrinder/bot/rules/integer.py +2 -3
- telegrinder/bot/rules/is_from.py +12 -11
- telegrinder/bot/rules/logic.py +11 -5
- telegrinder/bot/rules/markup.py +22 -14
- telegrinder/bot/rules/mention.py +8 -7
- telegrinder/bot/rules/message_entities.py +8 -4
- telegrinder/bot/rules/node.py +23 -12
- telegrinder/bot/rules/payload.py +5 -4
- telegrinder/bot/rules/payment_invoice.py +6 -21
- telegrinder/bot/rules/regex.py +2 -4
- telegrinder/bot/rules/rule_enum.py +8 -7
- telegrinder/bot/rules/start.py +5 -6
- telegrinder/bot/rules/state.py +1 -1
- telegrinder/bot/rules/text.py +4 -15
- telegrinder/bot/rules/update.py +3 -4
- telegrinder/bot/scenario/__init__.py +0 -0
- telegrinder/bot/scenario/abc.py +6 -5
- telegrinder/bot/scenario/checkbox.py +1 -1
- telegrinder/bot/scenario/choice.py +30 -39
- telegrinder/client/__init__.py +3 -5
- telegrinder/client/abc.py +11 -6
- telegrinder/client/aiohttp.py +141 -27
- telegrinder/client/form_data.py +1 -1
- telegrinder/model.py +61 -89
- telegrinder/modules.py +325 -102
- telegrinder/msgspec_utils/__init__.py +40 -0
- telegrinder/msgspec_utils/abc.py +18 -0
- telegrinder/msgspec_utils/custom_types/__init__.py +6 -0
- telegrinder/msgspec_utils/custom_types/datetime.py +24 -0
- telegrinder/msgspec_utils/custom_types/enum_meta.py +43 -0
- telegrinder/msgspec_utils/custom_types/literal.py +25 -0
- telegrinder/msgspec_utils/custom_types/option.py +17 -0
- telegrinder/msgspec_utils/decoder.py +389 -0
- telegrinder/msgspec_utils/encoder.py +206 -0
- telegrinder/{msgspec_json.py → msgspec_utils/json.py} +6 -5
- telegrinder/msgspec_utils/tools.py +75 -0
- telegrinder/node/__init__.py +24 -7
- telegrinder/node/attachment.py +1 -0
- telegrinder/node/base.py +154 -72
- telegrinder/node/callback_query.py +5 -5
- telegrinder/node/collection.py +39 -0
- telegrinder/node/command.py +1 -2
- telegrinder/node/composer.py +121 -72
- telegrinder/node/container.py +11 -8
- telegrinder/node/context.py +48 -0
- telegrinder/node/either.py +27 -40
- telegrinder/node/error.py +41 -0
- telegrinder/node/event.py +37 -11
- telegrinder/node/exceptions.py +7 -0
- telegrinder/node/file.py +0 -0
- telegrinder/node/i18n.py +108 -0
- telegrinder/node/me.py +3 -2
- telegrinder/node/payload.py +1 -1
- telegrinder/node/polymorphic.py +63 -28
- telegrinder/node/reply_message.py +12 -0
- telegrinder/node/rule.py +6 -13
- telegrinder/node/scope.py +14 -5
- telegrinder/node/session.py +53 -0
- telegrinder/node/source.py +41 -9
- telegrinder/node/text.py +1 -2
- telegrinder/node/tools/__init__.py +0 -0
- telegrinder/node/tools/generator.py +3 -5
- telegrinder/node/utility.py +16 -0
- telegrinder/py.typed +0 -0
- telegrinder/rules.py +0 -0
- telegrinder/tools/__init__.py +48 -88
- telegrinder/tools/aio.py +103 -0
- telegrinder/tools/callback_data_serialization/__init__.py +5 -0
- telegrinder/tools/{callback_data_serilization → callback_data_serialization}/abc.py +0 -0
- telegrinder/tools/{callback_data_serilization → callback_data_serialization}/json_ser.py +2 -3
- telegrinder/tools/{callback_data_serilization → callback_data_serialization}/msgpack_ser.py +45 -27
- telegrinder/tools/final.py +21 -0
- telegrinder/tools/formatting/__init__.py +2 -18
- telegrinder/tools/formatting/deep_links/__init__.py +39 -0
- telegrinder/tools/formatting/{deep_links.py → deep_links/links.py} +12 -85
- telegrinder/tools/formatting/deep_links/parsing.py +90 -0
- telegrinder/tools/formatting/deep_links/validators.py +8 -0
- telegrinder/tools/formatting/html_formatter.py +18 -45
- telegrinder/tools/fullname.py +83 -0
- telegrinder/tools/global_context/__init__.py +4 -3
- telegrinder/tools/global_context/abc.py +17 -14
- telegrinder/tools/global_context/builtin_context.py +39 -0
- telegrinder/tools/global_context/global_context.py +138 -39
- telegrinder/tools/input_file_directory.py +0 -0
- telegrinder/tools/keyboard/__init__.py +39 -0
- telegrinder/tools/keyboard/abc.py +159 -0
- telegrinder/tools/keyboard/base.py +77 -0
- telegrinder/tools/keyboard/buttons/__init__.py +14 -0
- telegrinder/tools/keyboard/buttons/base.py +18 -0
- telegrinder/tools/{buttons.py → keyboard/buttons/buttons.py} +71 -23
- telegrinder/tools/keyboard/buttons/static_buttons.py +56 -0
- telegrinder/tools/keyboard/buttons/tools.py +18 -0
- telegrinder/tools/keyboard/data.py +20 -0
- telegrinder/tools/keyboard/keyboard.py +131 -0
- telegrinder/tools/keyboard/static_keyboard.py +83 -0
- telegrinder/tools/lifespan.py +87 -51
- telegrinder/tools/limited_dict.py +4 -1
- telegrinder/tools/loop_wrapper.py +332 -0
- telegrinder/tools/magic/__init__.py +32 -0
- telegrinder/tools/magic/annotations.py +165 -0
- telegrinder/tools/magic/dictionary.py +20 -0
- telegrinder/tools/magic/function.py +246 -0
- telegrinder/tools/magic/shortcut.py +111 -0
- telegrinder/tools/parse_mode.py +9 -3
- telegrinder/tools/singleton/__init__.py +4 -0
- telegrinder/tools/singleton/abc.py +14 -0
- telegrinder/tools/singleton/singleton.py +18 -0
- telegrinder/tools/state_storage/__init__.py +0 -0
- telegrinder/tools/state_storage/abc.py +6 -1
- telegrinder/tools/state_storage/memory.py +1 -1
- telegrinder/tools/strings.py +0 -0
- telegrinder/types/__init__.py +307 -268
- telegrinder/types/enums.py +68 -37
- telegrinder/types/input_file.py +3 -3
- telegrinder/types/methods.py +5699 -5055
- telegrinder/types/methods_utils.py +62 -0
- telegrinder/types/objects.py +1782 -994
- telegrinder/verification_utils.py +3 -1
- telegrinder-0.5.1.dist-info/METADATA +162 -0
- telegrinder-0.5.1.dist-info/RECORD +200 -0
- {telegrinder-0.4.2.dist-info → telegrinder-0.5.1.dist-info}/licenses/LICENSE +2 -2
- telegrinder/bot/dispatch/waiter_machine/hasher/state.py +0 -20
- telegrinder/bot/rules/id.py +0 -24
- telegrinder/bot/rules/message.py +0 -15
- telegrinder/client/sonic.py +0 -212
- telegrinder/msgspec_utils.py +0 -478
- telegrinder/tools/adapter/__init__.py +0 -19
- telegrinder/tools/adapter/abc.py +0 -49
- telegrinder/tools/adapter/dataclass.py +0 -56
- telegrinder/tools/adapter/errors.py +0 -5
- telegrinder/tools/adapter/event.py +0 -61
- telegrinder/tools/adapter/node.py +0 -46
- telegrinder/tools/adapter/raw_event.py +0 -27
- telegrinder/tools/adapter/raw_update.py +0 -30
- telegrinder/tools/callback_data_serilization/__init__.py +0 -5
- telegrinder/tools/error_handler/__init__.py +0 -10
- telegrinder/tools/error_handler/abc.py +0 -30
- telegrinder/tools/error_handler/error.py +0 -9
- telegrinder/tools/error_handler/error_handler.py +0 -179
- telegrinder/tools/formatting/spec_html_formats.py +0 -75
- telegrinder/tools/functional.py +0 -8
- telegrinder/tools/global_context/telegrinder_ctx.py +0 -27
- telegrinder/tools/i18n/__init__.py +0 -12
- telegrinder/tools/i18n/abc.py +0 -32
- telegrinder/tools/i18n/middleware/__init__.py +0 -3
- telegrinder/tools/i18n/middleware/abc.py +0 -22
- telegrinder/tools/i18n/simple.py +0 -43
- telegrinder/tools/keyboard.py +0 -132
- telegrinder/tools/loop_wrapper/__init__.py +0 -4
- telegrinder/tools/loop_wrapper/abc.py +0 -20
- telegrinder/tools/loop_wrapper/loop_wrapper.py +0 -169
- telegrinder/tools/magic.py +0 -344
- telegrinder-0.4.2.dist-info/METADATA +0 -151
- telegrinder-0.4.2.dist-info/RECORD +0 -182
- {telegrinder-0.4.2.dist-info → telegrinder-0.5.1.dist-info}/WHEEL +0 -0
|
@@ -1,139 +1,260 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import asyncio
|
|
2
4
|
import sys
|
|
3
5
|
import typing
|
|
4
6
|
from http import HTTPStatus
|
|
5
7
|
|
|
6
8
|
import msgspec
|
|
7
|
-
from fntypes.
|
|
9
|
+
from fntypes.misc import is_ok
|
|
8
10
|
|
|
9
|
-
from telegrinder.api.api import API
|
|
11
|
+
from telegrinder.api.api import API
|
|
10
12
|
from telegrinder.api.error import APIServerError, InvalidTokenError
|
|
11
13
|
from telegrinder.bot.polling.abc import ABCPolling
|
|
12
14
|
from telegrinder.modules import logger
|
|
13
15
|
from telegrinder.msgspec_utils import decoder
|
|
16
|
+
from telegrinder.tools.aio import maybe_awaitable
|
|
14
17
|
from telegrinder.types.objects import Update, UpdateType
|
|
15
18
|
|
|
19
|
+
DEFAULT_OFFSET: typing.Final[int] = 0
|
|
20
|
+
DEFAULT_RECONNECT_AFTER: typing.Final[float] = 5.0
|
|
21
|
+
DEFAULT_MAX_RECONNECTS: typing.Final[int] = 15
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _compute_number(
|
|
25
|
+
default: int | float,
|
|
26
|
+
input_value: int | float,
|
|
27
|
+
conditional_value: int | float,
|
|
28
|
+
/,
|
|
29
|
+
) -> int | float:
|
|
30
|
+
return max(default, input_value) * (input_value <= conditional_value) + input_value * (
|
|
31
|
+
input_value >= conditional_value
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class PollingErrorHandler:
|
|
36
|
+
_handlers: dict[type[BaseException], typing.Callable[[BaseException], typing.Any]]
|
|
37
|
+
|
|
38
|
+
__slots__ = ("_polling", "_handlers")
|
|
39
|
+
|
|
40
|
+
def __init__(self, polling: Polling, /) -> None:
|
|
41
|
+
self._polling = polling
|
|
42
|
+
self._handlers = { # type: ignore
|
|
43
|
+
InvalidTokenError: self._handle_invalid_token_error,
|
|
44
|
+
asyncio.CancelledError: self._handle_cancelled_error,
|
|
45
|
+
APIServerError: self._handle_api_server_error,
|
|
46
|
+
**{e: self._handle_connection_timeout_error for e in polling.api.http.CONNECTION_TIMEOUT_ERRORS},
|
|
47
|
+
**{e: self._handle_client_connection_error for e in polling.api.http.CLIENT_CONNECTION_ERRORS},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async def handle(self, error: BaseException) -> bool:
|
|
51
|
+
error_class = type(error)
|
|
52
|
+
|
|
53
|
+
if error_class is SystemExit:
|
|
54
|
+
self._handle_system_exit(error) # type: ignore
|
|
55
|
+
|
|
56
|
+
if error_class not in self._handlers:
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
await maybe_awaitable(self._handlers[error_class](error))
|
|
61
|
+
return True
|
|
62
|
+
except SystemExit as sys_exit_err:
|
|
63
|
+
self._handle_system_exit(sys_exit_err)
|
|
64
|
+
|
|
65
|
+
def _handle_system_exit(self, error: SystemExit) -> typing.NoReturn:
|
|
66
|
+
logger.error(f"Forced exit from the program with code {error.code}.")
|
|
67
|
+
raise error from None
|
|
68
|
+
|
|
69
|
+
def _handle_invalid_token_error(
|
|
70
|
+
self,
|
|
71
|
+
error: InvalidTokenError,
|
|
72
|
+
) -> typing.NoReturn:
|
|
73
|
+
logger.error(error)
|
|
74
|
+
self._polling.stop()
|
|
75
|
+
sys.exit(3)
|
|
76
|
+
|
|
77
|
+
def _handle_cancelled_error(self, _: asyncio.CancelledError) -> None:
|
|
78
|
+
logger.info("Caught cancel, stopping polling...")
|
|
79
|
+
self._polling.stop()
|
|
80
|
+
|
|
81
|
+
async def _handle_connection_timeout_error(self, _: BaseException) -> None:
|
|
82
|
+
if self._polling.reconnects_counter > self._polling.max_reconnects:
|
|
83
|
+
logger.error(
|
|
84
|
+
"Failed to reconnect to Telegram API server after {} attempts, stopping polling...",
|
|
85
|
+
self._polling.max_reconnects,
|
|
86
|
+
)
|
|
87
|
+
self._polling.stop()
|
|
88
|
+
sys.exit(6)
|
|
89
|
+
|
|
90
|
+
logger.warning(
|
|
91
|
+
"Server disconnected, waiting {} seconds to reconnect...",
|
|
92
|
+
self._polling.reconnect_after,
|
|
93
|
+
)
|
|
94
|
+
await asyncio.sleep(self._polling.reconnect_after)
|
|
95
|
+
|
|
96
|
+
async def _handle_client_connection_error(self, _: BaseException) -> None:
|
|
97
|
+
logger.error(
|
|
98
|
+
"Client connection failed, attempt to reconnect after {} seconds...",
|
|
99
|
+
self._polling.reconnect_after,
|
|
100
|
+
)
|
|
101
|
+
await asyncio.sleep(self._polling.reconnect_after)
|
|
102
|
+
|
|
103
|
+
async def _handle_api_server_error(
|
|
104
|
+
self,
|
|
105
|
+
error: APIServerError,
|
|
106
|
+
) -> None:
|
|
107
|
+
logger.error(f"{error}, waiting {error.retry_after} seconds to the next request...")
|
|
108
|
+
await asyncio.sleep(error.retry_after)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class Polling(ABCPolling):
|
|
112
|
+
__slots__ = (
|
|
113
|
+
"api",
|
|
114
|
+
"timeout",
|
|
115
|
+
"limit",
|
|
116
|
+
"allowed_updates",
|
|
117
|
+
"reconnect_after",
|
|
118
|
+
"max_reconnects",
|
|
119
|
+
"offset",
|
|
120
|
+
"_running",
|
|
121
|
+
"_reconnects_counter",
|
|
122
|
+
"_error_handler",
|
|
123
|
+
)
|
|
16
124
|
|
|
17
|
-
class Polling(ABCPolling, typing.Generic[HTTPClient]):
|
|
18
125
|
def __init__(
|
|
19
126
|
self,
|
|
20
|
-
api: API
|
|
127
|
+
api: API,
|
|
21
128
|
*,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
129
|
+
timeout: int | None = None,
|
|
130
|
+
limit: int | None = None,
|
|
131
|
+
offset: int = DEFAULT_OFFSET,
|
|
132
|
+
reconnect_after: float = DEFAULT_RECONNECT_AFTER,
|
|
133
|
+
max_reconnects: int = DEFAULT_MAX_RECONNECTS,
|
|
134
|
+
include_updates: set[UpdateType] | None = None,
|
|
135
|
+
exclude_updates: set[UpdateType] | None = None,
|
|
27
136
|
) -> None:
|
|
28
137
|
self.api = api
|
|
138
|
+
self.timeout = timeout
|
|
139
|
+
self.limit = limit
|
|
29
140
|
self.allowed_updates = self.get_allowed_updates(
|
|
30
141
|
include_updates=include_updates,
|
|
31
142
|
exclude_updates=exclude_updates,
|
|
32
143
|
)
|
|
33
|
-
self.
|
|
34
|
-
self.
|
|
35
|
-
self.offset = offset
|
|
36
|
-
self.
|
|
144
|
+
self.reconnect_after = _compute_number(DEFAULT_RECONNECT_AFTER, reconnect_after, 0.0)
|
|
145
|
+
self.max_reconnects = _compute_number(DEFAULT_MAX_RECONNECTS, max_reconnects, 0)
|
|
146
|
+
self.offset = max(DEFAULT_OFFSET, offset)
|
|
147
|
+
self._running = False
|
|
148
|
+
self._reconnects_counter = 0
|
|
149
|
+
self._error_handler = PollingErrorHandler(self)
|
|
37
150
|
|
|
38
151
|
def __repr__(self) -> str:
|
|
39
152
|
return (
|
|
40
|
-
"<{}:
|
|
41
|
-
"
|
|
153
|
+
"<{}: api={!r}, running={}, offset={}, timeout={}, limit={}, "
|
|
154
|
+
"allowed_updates={!r}, max_reconnects={}, reconnect_after={}>"
|
|
42
155
|
).format(
|
|
43
|
-
self.
|
|
156
|
+
type(self).__name__,
|
|
44
157
|
self.api,
|
|
45
|
-
self.
|
|
158
|
+
self._running,
|
|
46
159
|
self.offset,
|
|
160
|
+
self.timeout,
|
|
161
|
+
self.limit,
|
|
47
162
|
self.allowed_updates,
|
|
48
|
-
self.
|
|
49
|
-
self.
|
|
163
|
+
self.max_reconnects,
|
|
164
|
+
self.reconnect_after,
|
|
50
165
|
)
|
|
51
166
|
|
|
52
167
|
@staticmethod
|
|
53
168
|
def get_allowed_updates(
|
|
54
169
|
*,
|
|
55
|
-
include_updates: set[
|
|
56
|
-
exclude_updates: set[
|
|
57
|
-
) -> list[
|
|
58
|
-
allowed_updates
|
|
59
|
-
if not include_updates and not exclude_updates:
|
|
60
|
-
return allowed_updates
|
|
170
|
+
include_updates: set[UpdateType] | None = None,
|
|
171
|
+
exclude_updates: set[UpdateType] | None = None,
|
|
172
|
+
) -> list[UpdateType]:
|
|
173
|
+
allowed_updates = list(UpdateType)
|
|
61
174
|
|
|
62
175
|
if include_updates and exclude_updates:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
176
|
+
return [x for x in allowed_updates if x in include_updates and x not in exclude_updates]
|
|
177
|
+
|
|
178
|
+
if exclude_updates:
|
|
179
|
+
return [x for x in allowed_updates if x not in exclude_updates]
|
|
180
|
+
|
|
181
|
+
if include_updates:
|
|
182
|
+
return [x for x in allowed_updates if x in include_updates]
|
|
68
183
|
|
|
69
|
-
return
|
|
184
|
+
return allowed_updates
|
|
185
|
+
|
|
186
|
+
@property
|
|
187
|
+
def reconnects_counter(self) -> int:
|
|
188
|
+
return self._reconnects_counter
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def running(self) -> bool:
|
|
192
|
+
return self._running
|
|
193
|
+
|
|
194
|
+
def _reset_reconnects_counter(self) -> None:
|
|
195
|
+
self._reconnects_counter = 0
|
|
70
196
|
|
|
71
197
|
async def get_updates(self) -> msgspec.Raw:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
198
|
+
try:
|
|
199
|
+
raw_updates = await self.api.request_raw(
|
|
200
|
+
method="getUpdates",
|
|
201
|
+
data=dict(
|
|
202
|
+
offset=self.offset,
|
|
203
|
+
limit=self.limit,
|
|
204
|
+
timeout=self.timeout,
|
|
205
|
+
allowed_updates=self.allowed_updates,
|
|
206
|
+
),
|
|
207
|
+
timeout=self.timeout or 0 + self.api.http.timeout,
|
|
208
|
+
)
|
|
209
|
+
except TimeoutError:
|
|
210
|
+
return msgspec.Raw(b"")
|
|
79
211
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
212
|
+
if is_ok(raw_updates):
|
|
213
|
+
return raw_updates.value
|
|
214
|
+
|
|
215
|
+
match (error := raw_updates.error).status_code:
|
|
216
|
+
case HTTPStatus.TOO_MANY_REQUESTS:
|
|
217
|
+
error = APIServerError(
|
|
218
|
+
message="Too many requests to get updates",
|
|
219
|
+
retry_after=error.retry_after.unwrap_or(int(self.reconnect_after)),
|
|
220
|
+
)
|
|
221
|
+
case HTTPStatus.UNAUTHORIZED | HTTPStatus.NOT_FOUND as status:
|
|
222
|
+
error = InvalidTokenError(
|
|
223
|
+
"Token seems to be invalid"
|
|
224
|
+
if status == HTTPStatus.NOT_FOUND
|
|
225
|
+
else "Invalid token (unauthorized)",
|
|
226
|
+
)
|
|
227
|
+
case HTTPStatus.BAD_GATEWAY | HTTPStatus.GATEWAY_TIMEOUT as status:
|
|
228
|
+
error = APIServerError(
|
|
229
|
+
message="Telegram API server responded a {}".format(status.name.replace("_", " ")),
|
|
230
|
+
retry_after=int(self.reconnect_after),
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
raise error from None
|
|
89
234
|
|
|
90
235
|
async def listen(self) -> typing.AsyncGenerator[list[Update], None]:
|
|
91
236
|
logger.debug("Listening polling")
|
|
92
|
-
|
|
93
|
-
self._stop = False
|
|
237
|
+
self._running = True
|
|
94
238
|
|
|
95
|
-
with decoder(list[Update]) as dec:
|
|
96
|
-
while
|
|
239
|
+
with decoder(list[Update]) as dec:
|
|
240
|
+
while self._running:
|
|
97
241
|
try:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
self.
|
|
104
|
-
except
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
await asyncio.sleep(self.reconnection_timeout)
|
|
111
|
-
except asyncio.CancelledError:
|
|
112
|
-
logger.info("Caught cancel, polling stopping...")
|
|
113
|
-
self.stop()
|
|
114
|
-
except self.api.http.CONNECTION_TIMEOUT_ERRORS:
|
|
115
|
-
if reconn_counter > self.max_reconnetions:
|
|
116
|
-
logger.error(
|
|
117
|
-
"Failed to reconnect to the server after {} attempts, polling stopping.",
|
|
118
|
-
self.max_reconnetions,
|
|
119
|
-
)
|
|
120
|
-
self.stop()
|
|
121
|
-
sys.exit(6)
|
|
122
|
-
else:
|
|
123
|
-
logger.warning(
|
|
124
|
-
"Server disconnected, waiting {} seconds to reconnect...",
|
|
125
|
-
self.reconnection_timeout,
|
|
126
|
-
)
|
|
127
|
-
reconn_counter += 1
|
|
128
|
-
await asyncio.sleep(self.reconnection_timeout)
|
|
129
|
-
except self.api.http.CLIENT_CONNECTION_ERRORS:
|
|
130
|
-
logger.error("Client connection failed, attempted to reconnect...")
|
|
131
|
-
await asyncio.sleep(self.reconnection_timeout)
|
|
132
|
-
except BaseException as e:
|
|
133
|
-
logger.exception("Traceback message below:")
|
|
242
|
+
if (raw := await self.get_updates()) and (updates := dec.decode(raw)):
|
|
243
|
+
yield updates
|
|
244
|
+
self.offset = updates[-1].update_id + 1
|
|
245
|
+
|
|
246
|
+
if self._reconnects_counter != 0:
|
|
247
|
+
self._reset_reconnects_counter()
|
|
248
|
+
except BaseException as error:
|
|
249
|
+
if not await self._error_handler.handle(error):
|
|
250
|
+
logger.exception("Traceback message below:")
|
|
251
|
+
|
|
252
|
+
if isinstance(error, self.api.http.CONNECTION_TIMEOUT_ERRORS):
|
|
253
|
+
self._reconnects_counter += 1
|
|
134
254
|
|
|
135
255
|
def stop(self) -> None:
|
|
136
|
-
self.
|
|
256
|
+
self._running = False
|
|
257
|
+
self._reset_reconnects_counter()
|
|
137
258
|
|
|
138
259
|
|
|
139
260
|
__all__ = ("Polling",)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from telegrinder.bot.rules.abc import ABCRule, AndRule, NotRule, OrRule
|
|
1
|
+
from telegrinder.bot.rules.abc import ABCRule, AndRule, NotRule, OrRule, check_rule
|
|
2
2
|
from telegrinder.bot.rules.callback_data import (
|
|
3
3
|
CallbackDataEq,
|
|
4
4
|
CallbackDataJsonEq,
|
|
@@ -6,11 +6,9 @@ from telegrinder.bot.rules.callback_data import (
|
|
|
6
6
|
CallbackDataMap,
|
|
7
7
|
CallbackDataMarkup,
|
|
8
8
|
CallbackQueryDataRule,
|
|
9
|
-
CallbackQueryRule,
|
|
10
9
|
HasData,
|
|
11
10
|
)
|
|
12
11
|
from telegrinder.bot.rules.chat_join import (
|
|
13
|
-
ChatJoinRequestRule,
|
|
14
12
|
HasInviteLink,
|
|
15
13
|
InviteLinkByCreator,
|
|
16
14
|
InviteLinkName,
|
|
@@ -19,12 +17,10 @@ from telegrinder.bot.rules.command import Argument, Command
|
|
|
19
17
|
from telegrinder.bot.rules.enum_text import EnumTextRule
|
|
20
18
|
from telegrinder.bot.rules.func import FuncRule
|
|
21
19
|
from telegrinder.bot.rules.fuzzy import FuzzyText
|
|
22
|
-
from telegrinder.bot.rules.id import IdRule
|
|
23
20
|
from telegrinder.bot.rules.inline import (
|
|
24
21
|
HasLocation,
|
|
25
22
|
InlineQueryChatType,
|
|
26
23
|
InlineQueryMarkup,
|
|
27
|
-
InlineQueryRule,
|
|
28
24
|
InlineQueryText,
|
|
29
25
|
)
|
|
30
26
|
from telegrinder.bot.rules.integer import IntegerInRange, IsInteger
|
|
@@ -49,7 +45,6 @@ from telegrinder.bot.rules.is_from import (
|
|
|
49
45
|
from telegrinder.bot.rules.logic import If
|
|
50
46
|
from telegrinder.bot.rules.markup import Markup
|
|
51
47
|
from telegrinder.bot.rules.mention import HasMention
|
|
52
|
-
from telegrinder.bot.rules.message import MessageRule
|
|
53
48
|
from telegrinder.bot.rules.message_entities import HasEntities, MessageEntities
|
|
54
49
|
from telegrinder.bot.rules.node import NodeRule
|
|
55
50
|
from telegrinder.bot.rules.payload import (
|
|
@@ -59,10 +54,7 @@ from telegrinder.bot.rules.payload import (
|
|
|
59
54
|
PayloadModelRule,
|
|
60
55
|
PayloadRule,
|
|
61
56
|
)
|
|
62
|
-
from telegrinder.bot.rules.payment_invoice import
|
|
63
|
-
PaymentInvoiceCurrency,
|
|
64
|
-
PaymentInvoiceRule,
|
|
65
|
-
)
|
|
57
|
+
from telegrinder.bot.rules.payment_invoice import PaymentInvoiceCurrency
|
|
66
58
|
from telegrinder.bot.rules.regex import Regex
|
|
67
59
|
from telegrinder.bot.rules.rule_enum import RuleEnum
|
|
68
60
|
from telegrinder.bot.rules.start import StartCommand
|
|
@@ -80,8 +72,6 @@ __all__ = (
|
|
|
80
72
|
"CallbackDataMap",
|
|
81
73
|
"CallbackDataMarkup",
|
|
82
74
|
"CallbackQueryDataRule",
|
|
83
|
-
"CallbackQueryRule",
|
|
84
|
-
"ChatJoinRequestRule",
|
|
85
75
|
"Command",
|
|
86
76
|
"EnumTextRule",
|
|
87
77
|
"FuncRule",
|
|
@@ -93,11 +83,9 @@ __all__ = (
|
|
|
93
83
|
"HasLocation",
|
|
94
84
|
"HasMention",
|
|
95
85
|
"HasText",
|
|
96
|
-
"IdRule",
|
|
97
86
|
"If",
|
|
98
87
|
"InlineQueryChatType",
|
|
99
88
|
"InlineQueryMarkup",
|
|
100
|
-
"InlineQueryRule",
|
|
101
89
|
"InlineQueryText",
|
|
102
90
|
"IntegerInRange",
|
|
103
91
|
"InviteLinkByCreator",
|
|
@@ -122,7 +110,6 @@ __all__ = (
|
|
|
122
110
|
"IsUserId",
|
|
123
111
|
"Markup",
|
|
124
112
|
"MessageEntities",
|
|
125
|
-
"MessageRule",
|
|
126
113
|
"NodeRule",
|
|
127
114
|
"NotRule",
|
|
128
115
|
"OrRule",
|
|
@@ -132,11 +119,11 @@ __all__ = (
|
|
|
132
119
|
"PayloadModelRule",
|
|
133
120
|
"PayloadRule",
|
|
134
121
|
"PaymentInvoiceCurrency",
|
|
135
|
-
"PaymentInvoiceRule",
|
|
136
122
|
"Regex",
|
|
137
123
|
"RuleEnum",
|
|
138
124
|
"StartCommand",
|
|
139
125
|
"State",
|
|
140
126
|
"StateMeta",
|
|
141
127
|
"Text",
|
|
128
|
+
"check_rule",
|
|
142
129
|
)
|