telegrinder 0.3.4__py3-none-any.whl → 0.3.4.post1__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 +144 -144
- telegrinder/api/__init__.py +8 -8
- telegrinder/api/api.py +93 -93
- telegrinder/api/error.py +16 -16
- telegrinder/api/response.py +20 -20
- telegrinder/api/token.py +36 -36
- telegrinder/bot/__init__.py +66 -66
- telegrinder/bot/bot.py +76 -76
- telegrinder/bot/cute_types/__init__.py +17 -17
- telegrinder/bot/cute_types/base.py +258 -258
- telegrinder/bot/cute_types/callback_query.py +385 -385
- telegrinder/bot/cute_types/chat_join_request.py +61 -61
- telegrinder/bot/cute_types/chat_member_updated.py +160 -160
- telegrinder/bot/cute_types/inline_query.py +43 -43
- telegrinder/bot/cute_types/message.py +2637 -2637
- telegrinder/bot/cute_types/update.py +104 -104
- telegrinder/bot/cute_types/utils.py +95 -95
- telegrinder/bot/dispatch/__init__.py +55 -55
- telegrinder/bot/dispatch/abc.py +77 -77
- telegrinder/bot/dispatch/context.py +98 -98
- telegrinder/bot/dispatch/dispatch.py +202 -202
- telegrinder/bot/dispatch/handler/__init__.py +13 -13
- telegrinder/bot/dispatch/handler/abc.py +24 -24
- telegrinder/bot/dispatch/handler/audio_reply.py +44 -44
- telegrinder/bot/dispatch/handler/base.py +57 -57
- telegrinder/bot/dispatch/handler/document_reply.py +44 -44
- telegrinder/bot/dispatch/handler/func.py +135 -135
- telegrinder/bot/dispatch/handler/media_group_reply.py +43 -43
- telegrinder/bot/dispatch/handler/message_reply.py +36 -36
- telegrinder/bot/dispatch/handler/photo_reply.py +44 -44
- telegrinder/bot/dispatch/handler/sticker_reply.py +37 -37
- telegrinder/bot/dispatch/handler/video_reply.py +44 -44
- telegrinder/bot/dispatch/middleware/__init__.py +3 -3
- telegrinder/bot/dispatch/middleware/abc.py +22 -22
- telegrinder/bot/dispatch/process.py +157 -157
- telegrinder/bot/dispatch/return_manager/__init__.py +13 -13
- telegrinder/bot/dispatch/return_manager/abc.py +108 -108
- telegrinder/bot/dispatch/return_manager/callback_query.py +20 -20
- telegrinder/bot/dispatch/return_manager/inline_query.py +15 -15
- telegrinder/bot/dispatch/return_manager/message.py +36 -36
- telegrinder/bot/dispatch/view/__init__.py +13 -13
- telegrinder/bot/dispatch/view/abc.py +41 -41
- telegrinder/bot/dispatch/view/base.py +200 -200
- telegrinder/bot/dispatch/view/box.py +129 -129
- telegrinder/bot/dispatch/view/callback_query.py +17 -17
- telegrinder/bot/dispatch/view/chat_join_request.py +16 -16
- telegrinder/bot/dispatch/view/chat_member.py +39 -39
- telegrinder/bot/dispatch/view/inline_query.py +17 -17
- telegrinder/bot/dispatch/view/message.py +44 -44
- telegrinder/bot/dispatch/view/raw.py +114 -114
- telegrinder/bot/dispatch/waiter_machine/__init__.py +17 -17
- telegrinder/bot/dispatch/waiter_machine/actions.py +13 -13
- telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +8 -8
- telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +55 -55
- telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +57 -57
- telegrinder/bot/dispatch/waiter_machine/hasher/message.py +51 -51
- telegrinder/bot/dispatch/waiter_machine/hasher/state.py +19 -19
- telegrinder/bot/dispatch/waiter_machine/machine.py +172 -172
- telegrinder/bot/dispatch/waiter_machine/middleware.py +89 -89
- telegrinder/bot/dispatch/waiter_machine/short_state.py +68 -68
- telegrinder/bot/polling/__init__.py +4 -4
- telegrinder/bot/polling/abc.py +25 -25
- telegrinder/bot/polling/polling.py +131 -131
- telegrinder/bot/rules/__init__.py +62 -62
- telegrinder/bot/rules/abc.py +206 -206
- telegrinder/bot/rules/adapter/__init__.py +17 -17
- telegrinder/bot/rules/adapter/abc.py +31 -31
- telegrinder/bot/rules/adapter/errors.py +5 -5
- telegrinder/bot/rules/adapter/event.py +65 -65
- telegrinder/bot/rules/adapter/node.py +48 -48
- telegrinder/bot/rules/adapter/raw_event.py +27 -27
- telegrinder/bot/rules/adapter/raw_update.py +30 -30
- telegrinder/bot/rules/callback_data.py +163 -163
- telegrinder/bot/rules/chat_join.py +43 -43
- telegrinder/bot/rules/command.py +126 -126
- telegrinder/bot/rules/enum_text.py +36 -36
- telegrinder/bot/rules/func.py +26 -26
- telegrinder/bot/rules/fuzzy.py +24 -24
- telegrinder/bot/rules/inline.py +56 -56
- telegrinder/bot/rules/integer.py +20 -20
- telegrinder/bot/rules/is_from.py +127 -127
- telegrinder/bot/rules/markup.py +43 -43
- telegrinder/bot/rules/mention.py +14 -14
- telegrinder/bot/rules/message.py +17 -17
- telegrinder/bot/rules/message_entities.py +35 -35
- telegrinder/bot/rules/node.py +27 -27
- telegrinder/bot/rules/regex.py +37 -37
- telegrinder/bot/rules/rule_enum.py +72 -72
- telegrinder/bot/rules/start.py +42 -42
- telegrinder/bot/rules/state.py +37 -37
- telegrinder/bot/rules/text.py +33 -33
- telegrinder/bot/rules/update.py +15 -15
- telegrinder/bot/scenario/__init__.py +5 -5
- telegrinder/bot/scenario/abc.py +19 -19
- telegrinder/bot/scenario/checkbox.py +176 -176
- telegrinder/bot/scenario/choice.py +51 -51
- telegrinder/client/__init__.py +4 -4
- telegrinder/client/abc.py +75 -75
- telegrinder/client/aiohttp.py +130 -130
- telegrinder/model.py +313 -313
- telegrinder/modules.py +237 -237
- telegrinder/msgspec_json.py +14 -14
- telegrinder/msgspec_utils.py +410 -410
- telegrinder/node/__init__.py +20 -20
- telegrinder/node/attachment.py +87 -87
- telegrinder/node/base.py +157 -157
- telegrinder/node/callback_query.py +53 -53
- telegrinder/node/command.py +33 -33
- telegrinder/node/composer.py +198 -198
- telegrinder/node/container.py +27 -27
- telegrinder/node/event.py +65 -65
- telegrinder/node/me.py +16 -16
- telegrinder/node/message.py +14 -14
- telegrinder/node/polymorphic.py +48 -48
- telegrinder/node/rule.py +76 -76
- telegrinder/node/scope.py +38 -38
- telegrinder/node/source.py +71 -71
- telegrinder/node/text.py +41 -41
- telegrinder/node/tools/__init__.py +3 -3
- telegrinder/node/tools/generator.py +40 -40
- telegrinder/node/update.py +15 -15
- telegrinder/rules.py +5 -5
- telegrinder/tools/__init__.py +74 -74
- telegrinder/tools/buttons.py +79 -79
- telegrinder/tools/error_handler/__init__.py +7 -7
- telegrinder/tools/error_handler/abc.py +33 -33
- telegrinder/tools/error_handler/error.py +9 -9
- telegrinder/tools/error_handler/error_handler.py +193 -193
- telegrinder/tools/formatting/__init__.py +46 -46
- telegrinder/tools/formatting/html.py +283 -283
- telegrinder/tools/formatting/links.py +33 -33
- telegrinder/tools/formatting/spec_html_formats.py +111 -111
- telegrinder/tools/functional.py +12 -12
- telegrinder/tools/global_context/__init__.py +7 -7
- telegrinder/tools/global_context/abc.py +63 -63
- telegrinder/tools/global_context/global_context.py +412 -412
- telegrinder/tools/global_context/telegrinder_ctx.py +27 -27
- telegrinder/tools/i18n/__init__.py +7 -7
- telegrinder/tools/i18n/abc.py +30 -30
- telegrinder/tools/i18n/middleware/__init__.py +3 -3
- telegrinder/tools/i18n/middleware/abc.py +25 -25
- telegrinder/tools/i18n/simple.py +43 -43
- telegrinder/tools/kb_set/__init__.py +4 -4
- telegrinder/tools/kb_set/base.py +15 -15
- telegrinder/tools/kb_set/yaml.py +63 -63
- telegrinder/tools/keyboard.py +128 -128
- telegrinder/tools/limited_dict.py +37 -37
- telegrinder/tools/loop_wrapper/__init__.py +4 -4
- telegrinder/tools/loop_wrapper/abc.py +15 -15
- telegrinder/tools/loop_wrapper/loop_wrapper.py +224 -224
- telegrinder/tools/magic.py +157 -157
- telegrinder/tools/parse_mode.py +6 -6
- telegrinder/tools/state_storage/__init__.py +4 -4
- telegrinder/tools/state_storage/abc.py +35 -35
- telegrinder/tools/state_storage/memory.py +25 -25
- telegrinder/types/__init__.py +260 -260
- telegrinder/types/enums.py +701 -701
- telegrinder/types/methods.py +4633 -4633
- telegrinder/types/objects.py +6950 -6950
- telegrinder/verification_utils.py +32 -32
- {telegrinder-0.3.4.dist-info → telegrinder-0.3.4.post1.dist-info}/LICENSE +22 -22
- {telegrinder-0.3.4.dist-info → telegrinder-0.3.4.post1.dist-info}/METADATA +1 -1
- telegrinder-0.3.4.post1.dist-info/RECORD +165 -0
- telegrinder-0.3.4.dist-info/RECORD +0 -165
- {telegrinder-0.3.4.dist-info → telegrinder-0.3.4.post1.dist-info}/WHEEL +0 -0
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import dataclasses
|
|
3
|
-
import datetime
|
|
4
|
-
import typing
|
|
5
|
-
from contextlib import suppress
|
|
6
|
-
|
|
7
|
-
from telegrinder.bot.cute_types import BaseCute
|
|
8
|
-
from telegrinder.bot.dispatch.context import Context
|
|
9
|
-
from telegrinder.bot.dispatch.handler.abc import ABCHandler
|
|
10
|
-
from telegrinder.bot.rules.abc import ABCRule
|
|
11
|
-
from telegrinder.model import Model
|
|
12
|
-
|
|
13
|
-
if typing.TYPE_CHECKING:
|
|
14
|
-
from .actions import WaiterActions
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
T = typing.TypeVar("T", bound=Model)
|
|
18
|
-
EventModel = typing.TypeVar("EventModel", bound=BaseCute)
|
|
19
|
-
|
|
20
|
-
Behaviour: typing.TypeAlias = ABCHandler[T] | None
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class ShortStateContext(typing.Generic[EventModel], typing.NamedTuple):
|
|
24
|
-
event: EventModel
|
|
25
|
-
context: Context
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@dataclasses.dataclass(slots=True)
|
|
29
|
-
class ShortState(typing.Generic[EventModel]):
|
|
30
|
-
event: asyncio.Event
|
|
31
|
-
actions: "WaiterActions[EventModel]"
|
|
32
|
-
|
|
33
|
-
release: ABCRule | None = dataclasses.field(
|
|
34
|
-
default=None,
|
|
35
|
-
kw_only=True,
|
|
36
|
-
)
|
|
37
|
-
filter: ABCRule | None = dataclasses.field(
|
|
38
|
-
default=None,
|
|
39
|
-
kw_only=True,
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
lifetime: dataclasses.InitVar[datetime.timedelta | None] = dataclasses.field(
|
|
43
|
-
default=None,
|
|
44
|
-
kw_only=True,
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
expiration_date: datetime.datetime | None = dataclasses.field(init=False, kw_only=True)
|
|
48
|
-
creation_date: datetime.datetime = dataclasses.field(init=False)
|
|
49
|
-
context: ShortStateContext[EventModel] | None = dataclasses.field(default=None, init=False, kw_only=True)
|
|
50
|
-
|
|
51
|
-
def __post_init__(self, expiration: datetime.timedelta | None = None) -> None:
|
|
52
|
-
self.creation_date = datetime.datetime.now()
|
|
53
|
-
self.expiration_date = (self.creation_date + expiration) if expiration is not None else None
|
|
54
|
-
|
|
55
|
-
async def cancel(self) -> None:
|
|
56
|
-
"""Cancel schedule waiters."""
|
|
57
|
-
|
|
58
|
-
waiters = typing.cast(
|
|
59
|
-
typing.Iterable[asyncio.Future[typing.Any]],
|
|
60
|
-
self.event._waiters, # type: ignore
|
|
61
|
-
)
|
|
62
|
-
for future in waiters:
|
|
63
|
-
future.cancel()
|
|
64
|
-
with suppress(asyncio.CancelledError):
|
|
65
|
-
await future
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
__all__ = ("ShortState", "ShortStateContext")
|
|
1
|
+
import asyncio
|
|
2
|
+
import dataclasses
|
|
3
|
+
import datetime
|
|
4
|
+
import typing
|
|
5
|
+
from contextlib import suppress
|
|
6
|
+
|
|
7
|
+
from telegrinder.bot.cute_types import BaseCute
|
|
8
|
+
from telegrinder.bot.dispatch.context import Context
|
|
9
|
+
from telegrinder.bot.dispatch.handler.abc import ABCHandler
|
|
10
|
+
from telegrinder.bot.rules.abc import ABCRule
|
|
11
|
+
from telegrinder.model import Model
|
|
12
|
+
|
|
13
|
+
if typing.TYPE_CHECKING:
|
|
14
|
+
from .actions import WaiterActions
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
T = typing.TypeVar("T", bound=Model)
|
|
18
|
+
EventModel = typing.TypeVar("EventModel", bound=BaseCute)
|
|
19
|
+
|
|
20
|
+
Behaviour: typing.TypeAlias = ABCHandler[T] | None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ShortStateContext(typing.Generic[EventModel], typing.NamedTuple):
|
|
24
|
+
event: EventModel
|
|
25
|
+
context: Context
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclasses.dataclass(slots=True)
|
|
29
|
+
class ShortState(typing.Generic[EventModel]):
|
|
30
|
+
event: asyncio.Event
|
|
31
|
+
actions: "WaiterActions[EventModel]"
|
|
32
|
+
|
|
33
|
+
release: ABCRule | None = dataclasses.field(
|
|
34
|
+
default=None,
|
|
35
|
+
kw_only=True,
|
|
36
|
+
)
|
|
37
|
+
filter: ABCRule | None = dataclasses.field(
|
|
38
|
+
default=None,
|
|
39
|
+
kw_only=True,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
lifetime: dataclasses.InitVar[datetime.timedelta | None] = dataclasses.field(
|
|
43
|
+
default=None,
|
|
44
|
+
kw_only=True,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
expiration_date: datetime.datetime | None = dataclasses.field(init=False, kw_only=True)
|
|
48
|
+
creation_date: datetime.datetime = dataclasses.field(init=False)
|
|
49
|
+
context: ShortStateContext[EventModel] | None = dataclasses.field(default=None, init=False, kw_only=True)
|
|
50
|
+
|
|
51
|
+
def __post_init__(self, expiration: datetime.timedelta | None = None) -> None:
|
|
52
|
+
self.creation_date = datetime.datetime.now()
|
|
53
|
+
self.expiration_date = (self.creation_date + expiration) if expiration is not None else None
|
|
54
|
+
|
|
55
|
+
async def cancel(self) -> None:
|
|
56
|
+
"""Cancel schedule waiters."""
|
|
57
|
+
|
|
58
|
+
waiters = typing.cast(
|
|
59
|
+
typing.Iterable[asyncio.Future[typing.Any]],
|
|
60
|
+
self.event._waiters, # type: ignore
|
|
61
|
+
)
|
|
62
|
+
for future in waiters:
|
|
63
|
+
future.cancel()
|
|
64
|
+
with suppress(asyncio.CancelledError):
|
|
65
|
+
await future
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
__all__ = ("ShortState", "ShortStateContext")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from .abc import ABCPolling
|
|
2
|
-
from .polling import Polling
|
|
3
|
-
|
|
4
|
-
__all__ = ("ABCPolling", "Polling")
|
|
1
|
+
from .abc import ABCPolling
|
|
2
|
+
from .polling import Polling
|
|
3
|
+
|
|
4
|
+
__all__ = ("ABCPolling", "Polling")
|
telegrinder/bot/polling/abc.py
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import typing
|
|
2
|
-
from abc import ABC, abstractmethod
|
|
3
|
-
|
|
4
|
-
import msgspec
|
|
5
|
-
|
|
6
|
-
from telegrinder.types.objects import Update
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class ABCPolling(ABC):
|
|
10
|
-
offset: int
|
|
11
|
-
|
|
12
|
-
@abstractmethod
|
|
13
|
-
async def get_updates(self) -> list[msgspec.Raw]:
|
|
14
|
-
pass
|
|
15
|
-
|
|
16
|
-
@abstractmethod
|
|
17
|
-
async def listen(self) -> typing.AsyncGenerator[list[Update], None]:
|
|
18
|
-
yield []
|
|
19
|
-
|
|
20
|
-
@abstractmethod
|
|
21
|
-
def stop(self) -> None:
|
|
22
|
-
pass
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
__all__ = ("ABCPolling",)
|
|
1
|
+
import typing
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
|
|
4
|
+
import msgspec
|
|
5
|
+
|
|
6
|
+
from telegrinder.types.objects import Update
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ABCPolling(ABC):
|
|
10
|
+
offset: int
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
async def get_updates(self) -> list[msgspec.Raw]:
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
async def listen(self) -> typing.AsyncGenerator[list[Update], None]:
|
|
18
|
+
yield []
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def stop(self) -> None:
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = ("ABCPolling",)
|
|
@@ -1,131 +1,131 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import typing
|
|
3
|
-
|
|
4
|
-
import aiohttp
|
|
5
|
-
import msgspec
|
|
6
|
-
from fntypes.result import Error, Ok
|
|
7
|
-
|
|
8
|
-
from telegrinder.api.api import API
|
|
9
|
-
from telegrinder.api.error import InvalidTokenError
|
|
10
|
-
from telegrinder.bot.polling.abc import ABCPolling
|
|
11
|
-
from telegrinder.modules import logger
|
|
12
|
-
from telegrinder.msgspec_utils import decoder
|
|
13
|
-
from telegrinder.types.objects import Update, UpdateType
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class Polling(ABCPolling):
|
|
17
|
-
def __init__(
|
|
18
|
-
self,
|
|
19
|
-
api: API,
|
|
20
|
-
*,
|
|
21
|
-
offset: int = 0,
|
|
22
|
-
reconnection_timeout: float = 5,
|
|
23
|
-
max_reconnetions: int = 10,
|
|
24
|
-
include_updates: set[str | UpdateType] | None = None,
|
|
25
|
-
exclude_updates: set[str | UpdateType] | None = None,
|
|
26
|
-
) -> None:
|
|
27
|
-
self.api = api
|
|
28
|
-
self.allowed_updates = self.get_allowed_updates(
|
|
29
|
-
include_updates=include_updates,
|
|
30
|
-
exclude_updates=exclude_updates,
|
|
31
|
-
)
|
|
32
|
-
self.reconnection_timeout = 5.0 if reconnection_timeout < 0 else reconnection_timeout
|
|
33
|
-
self.max_reconnetions = 10 if max_reconnetions < 0 else max_reconnetions
|
|
34
|
-
self.offset = offset
|
|
35
|
-
self._stop = False
|
|
36
|
-
|
|
37
|
-
def __repr__(self) -> str:
|
|
38
|
-
return (
|
|
39
|
-
"<{}: with api={!r}, stopped={}, offset={}, allowed_updates={!r}, "
|
|
40
|
-
"max_reconnetions={}, reconnection_timeout={}>"
|
|
41
|
-
).format(
|
|
42
|
-
self.__class__.__name__,
|
|
43
|
-
self.api,
|
|
44
|
-
self._stop,
|
|
45
|
-
self.offset,
|
|
46
|
-
self.allowed_updates,
|
|
47
|
-
self.max_reconnetions,
|
|
48
|
-
self.reconnection_timeout,
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
@staticmethod
|
|
52
|
-
def get_allowed_updates(
|
|
53
|
-
*,
|
|
54
|
-
include_updates: set[str | UpdateType] | None = None,
|
|
55
|
-
exclude_updates: set[str | UpdateType] | None = None,
|
|
56
|
-
) -> list[str]:
|
|
57
|
-
allowed_updates: list[str] = list(x.value for x in UpdateType)
|
|
58
|
-
if not include_updates and not exclude_updates:
|
|
59
|
-
return allowed_updates
|
|
60
|
-
|
|
61
|
-
if include_updates and exclude_updates:
|
|
62
|
-
allowed_updates = [
|
|
63
|
-
x for x in allowed_updates if x in include_updates and x not in exclude_updates
|
|
64
|
-
]
|
|
65
|
-
elif exclude_updates:
|
|
66
|
-
allowed_updates = [x for x in allowed_updates if x not in exclude_updates]
|
|
67
|
-
elif include_updates:
|
|
68
|
-
allowed_updates = [x for x in allowed_updates if x in include_updates]
|
|
69
|
-
|
|
70
|
-
return [x.value if isinstance(x, UpdateType) else x for x in allowed_updates]
|
|
71
|
-
|
|
72
|
-
async def get_updates(self) -> msgspec.Raw | None:
|
|
73
|
-
raw_updates = await self.api.request_raw(
|
|
74
|
-
"getUpdates",
|
|
75
|
-
{
|
|
76
|
-
"offset": self.offset,
|
|
77
|
-
"allowed_updates": self.allowed_updates,
|
|
78
|
-
},
|
|
79
|
-
)
|
|
80
|
-
match raw_updates:
|
|
81
|
-
case Ok(value):
|
|
82
|
-
return value
|
|
83
|
-
case Error(err) if err.code in (401, 404):
|
|
84
|
-
raise InvalidTokenError("Token seems to be invalid")
|
|
85
|
-
|
|
86
|
-
async def listen(self) -> typing.AsyncGenerator[list[Update], None]:
|
|
87
|
-
logger.debug("Listening polling")
|
|
88
|
-
reconn_counter = 0
|
|
89
|
-
|
|
90
|
-
while not self._stop:
|
|
91
|
-
try:
|
|
92
|
-
updates = await self.get_updates()
|
|
93
|
-
reconn_counter = 0
|
|
94
|
-
if not updates:
|
|
95
|
-
continue
|
|
96
|
-
updates_list: list[Update] = decoder.decode(updates, type=list[Update])
|
|
97
|
-
if updates_list:
|
|
98
|
-
yield updates_list
|
|
99
|
-
self.offset = updates_list[-1].update_id + 1
|
|
100
|
-
except InvalidTokenError as e:
|
|
101
|
-
logger.error(e)
|
|
102
|
-
self.stop()
|
|
103
|
-
exit(3)
|
|
104
|
-
except asyncio.CancelledError:
|
|
105
|
-
logger.info("Caught cancel, polling stopping...")
|
|
106
|
-
self.stop()
|
|
107
|
-
except (aiohttp.client.ServerConnectionError, TimeoutError):
|
|
108
|
-
if reconn_counter > self.max_reconnetions:
|
|
109
|
-
logger.error(
|
|
110
|
-
"Failed to reconnect to the server after {} attempts, polling stopping.",
|
|
111
|
-
self.max_reconnetions,
|
|
112
|
-
)
|
|
113
|
-
self.stop()
|
|
114
|
-
exit(6)
|
|
115
|
-
else:
|
|
116
|
-
logger.warning(
|
|
117
|
-
"Server disconnected, waiting 5 seconds to reconnect...",
|
|
118
|
-
)
|
|
119
|
-
reconn_counter += 1
|
|
120
|
-
await asyncio.sleep(self.reconnection_timeout)
|
|
121
|
-
except (aiohttp.ClientConnectorError, aiohttp.ClientOSError):
|
|
122
|
-
logger.error("Client connection failed, attempted to reconnect...")
|
|
123
|
-
await asyncio.sleep(self.reconnection_timeout)
|
|
124
|
-
except BaseException as e:
|
|
125
|
-
logger.exception(e)
|
|
126
|
-
|
|
127
|
-
def stop(self) -> None:
|
|
128
|
-
self._stop = True
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
__all__ = ("Polling",)
|
|
1
|
+
import asyncio
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
import aiohttp
|
|
5
|
+
import msgspec
|
|
6
|
+
from fntypes.result import Error, Ok
|
|
7
|
+
|
|
8
|
+
from telegrinder.api.api import API
|
|
9
|
+
from telegrinder.api.error import InvalidTokenError
|
|
10
|
+
from telegrinder.bot.polling.abc import ABCPolling
|
|
11
|
+
from telegrinder.modules import logger
|
|
12
|
+
from telegrinder.msgspec_utils import decoder
|
|
13
|
+
from telegrinder.types.objects import Update, UpdateType
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Polling(ABCPolling):
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
api: API,
|
|
20
|
+
*,
|
|
21
|
+
offset: int = 0,
|
|
22
|
+
reconnection_timeout: float = 5,
|
|
23
|
+
max_reconnetions: int = 10,
|
|
24
|
+
include_updates: set[str | UpdateType] | None = None,
|
|
25
|
+
exclude_updates: set[str | UpdateType] | None = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
self.api = api
|
|
28
|
+
self.allowed_updates = self.get_allowed_updates(
|
|
29
|
+
include_updates=include_updates,
|
|
30
|
+
exclude_updates=exclude_updates,
|
|
31
|
+
)
|
|
32
|
+
self.reconnection_timeout = 5.0 if reconnection_timeout < 0 else reconnection_timeout
|
|
33
|
+
self.max_reconnetions = 10 if max_reconnetions < 0 else max_reconnetions
|
|
34
|
+
self.offset = offset
|
|
35
|
+
self._stop = False
|
|
36
|
+
|
|
37
|
+
def __repr__(self) -> str:
|
|
38
|
+
return (
|
|
39
|
+
"<{}: with api={!r}, stopped={}, offset={}, allowed_updates={!r}, "
|
|
40
|
+
"max_reconnetions={}, reconnection_timeout={}>"
|
|
41
|
+
).format(
|
|
42
|
+
self.__class__.__name__,
|
|
43
|
+
self.api,
|
|
44
|
+
self._stop,
|
|
45
|
+
self.offset,
|
|
46
|
+
self.allowed_updates,
|
|
47
|
+
self.max_reconnetions,
|
|
48
|
+
self.reconnection_timeout,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def get_allowed_updates(
|
|
53
|
+
*,
|
|
54
|
+
include_updates: set[str | UpdateType] | None = None,
|
|
55
|
+
exclude_updates: set[str | UpdateType] | None = None,
|
|
56
|
+
) -> list[str]:
|
|
57
|
+
allowed_updates: list[str] = list(x.value for x in UpdateType)
|
|
58
|
+
if not include_updates and not exclude_updates:
|
|
59
|
+
return allowed_updates
|
|
60
|
+
|
|
61
|
+
if include_updates and exclude_updates:
|
|
62
|
+
allowed_updates = [
|
|
63
|
+
x for x in allowed_updates if x in include_updates and x not in exclude_updates
|
|
64
|
+
]
|
|
65
|
+
elif exclude_updates:
|
|
66
|
+
allowed_updates = [x for x in allowed_updates if x not in exclude_updates]
|
|
67
|
+
elif include_updates:
|
|
68
|
+
allowed_updates = [x for x in allowed_updates if x in include_updates]
|
|
69
|
+
|
|
70
|
+
return [x.value if isinstance(x, UpdateType) else x for x in allowed_updates]
|
|
71
|
+
|
|
72
|
+
async def get_updates(self) -> msgspec.Raw | None:
|
|
73
|
+
raw_updates = await self.api.request_raw(
|
|
74
|
+
"getUpdates",
|
|
75
|
+
{
|
|
76
|
+
"offset": self.offset,
|
|
77
|
+
"allowed_updates": self.allowed_updates,
|
|
78
|
+
},
|
|
79
|
+
)
|
|
80
|
+
match raw_updates:
|
|
81
|
+
case Ok(value):
|
|
82
|
+
return value
|
|
83
|
+
case Error(err) if err.code in (401, 404):
|
|
84
|
+
raise InvalidTokenError("Token seems to be invalid")
|
|
85
|
+
|
|
86
|
+
async def listen(self) -> typing.AsyncGenerator[list[Update], None]:
|
|
87
|
+
logger.debug("Listening polling")
|
|
88
|
+
reconn_counter = 0
|
|
89
|
+
|
|
90
|
+
while not self._stop:
|
|
91
|
+
try:
|
|
92
|
+
updates = await self.get_updates()
|
|
93
|
+
reconn_counter = 0
|
|
94
|
+
if not updates:
|
|
95
|
+
continue
|
|
96
|
+
updates_list: list[Update] = decoder.decode(updates, type=list[Update])
|
|
97
|
+
if updates_list:
|
|
98
|
+
yield updates_list
|
|
99
|
+
self.offset = updates_list[-1].update_id + 1
|
|
100
|
+
except InvalidTokenError as e:
|
|
101
|
+
logger.error(e)
|
|
102
|
+
self.stop()
|
|
103
|
+
exit(3)
|
|
104
|
+
except asyncio.CancelledError:
|
|
105
|
+
logger.info("Caught cancel, polling stopping...")
|
|
106
|
+
self.stop()
|
|
107
|
+
except (aiohttp.client.ServerConnectionError, TimeoutError):
|
|
108
|
+
if reconn_counter > self.max_reconnetions:
|
|
109
|
+
logger.error(
|
|
110
|
+
"Failed to reconnect to the server after {} attempts, polling stopping.",
|
|
111
|
+
self.max_reconnetions,
|
|
112
|
+
)
|
|
113
|
+
self.stop()
|
|
114
|
+
exit(6)
|
|
115
|
+
else:
|
|
116
|
+
logger.warning(
|
|
117
|
+
"Server disconnected, waiting 5 seconds to reconnect...",
|
|
118
|
+
)
|
|
119
|
+
reconn_counter += 1
|
|
120
|
+
await asyncio.sleep(self.reconnection_timeout)
|
|
121
|
+
except (aiohttp.ClientConnectorError, aiohttp.ClientOSError):
|
|
122
|
+
logger.error("Client connection failed, attempted to reconnect...")
|
|
123
|
+
await asyncio.sleep(self.reconnection_timeout)
|
|
124
|
+
except BaseException as e:
|
|
125
|
+
logger.exception(e)
|
|
126
|
+
|
|
127
|
+
def stop(self) -> None:
|
|
128
|
+
self._stop = True
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
__all__ = ("Polling",)
|
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
from telegrinder.bot.rules.abc import ABCRule, AndRule, NotRule, OrRule
|
|
2
|
-
from telegrinder.bot.rules.callback_data import (
|
|
3
|
-
CallbackDataEq,
|
|
4
|
-
CallbackDataJsonEq,
|
|
5
|
-
CallbackDataJsonModel,
|
|
6
|
-
CallbackDataMap,
|
|
7
|
-
CallbackDataMarkup,
|
|
8
|
-
CallbackQueryDataRule,
|
|
9
|
-
CallbackQueryRule,
|
|
10
|
-
HasData,
|
|
11
|
-
)
|
|
12
|
-
from telegrinder.bot.rules.chat_join import (
|
|
13
|
-
ChatJoinRequestRule,
|
|
14
|
-
HasInviteLink,
|
|
15
|
-
InviteLinkByCreator,
|
|
16
|
-
InviteLinkName,
|
|
17
|
-
)
|
|
18
|
-
from telegrinder.bot.rules.command import Argument, Command
|
|
19
|
-
from telegrinder.bot.rules.enum_text import EnumTextRule
|
|
20
|
-
from telegrinder.bot.rules.func import FuncRule
|
|
21
|
-
from telegrinder.bot.rules.fuzzy import FuzzyText
|
|
22
|
-
from telegrinder.bot.rules.inline import (
|
|
23
|
-
HasLocation,
|
|
24
|
-
InlineQueryChatType,
|
|
25
|
-
InlineQueryMarkup,
|
|
26
|
-
InlineQueryRule,
|
|
27
|
-
InlineQueryText,
|
|
28
|
-
)
|
|
29
|
-
from telegrinder.bot.rules.integer import IntegerInRange, IsInteger
|
|
30
|
-
from telegrinder.bot.rules.is_from import (
|
|
31
|
-
IsBot,
|
|
32
|
-
IsChat,
|
|
33
|
-
IsChatId,
|
|
34
|
-
IsDice,
|
|
35
|
-
IsDiceEmoji,
|
|
36
|
-
IsForum,
|
|
37
|
-
IsForward,
|
|
38
|
-
IsForwardType,
|
|
39
|
-
IsGroup,
|
|
40
|
-
IsLanguageCode,
|
|
41
|
-
IsPremium,
|
|
42
|
-
IsPrivate,
|
|
43
|
-
IsReply,
|
|
44
|
-
IsSuperGroup,
|
|
45
|
-
IsUser,
|
|
46
|
-
IsUserId,
|
|
47
|
-
)
|
|
48
|
-
from telegrinder.bot.rules.markup import Markup
|
|
49
|
-
from telegrinder.bot.rules.mention import HasMention
|
|
50
|
-
from telegrinder.bot.rules.message import MessageRule
|
|
51
|
-
from telegrinder.bot.rules.message_entities import HasEntities, MessageEntities
|
|
52
|
-
from telegrinder.bot.rules.node import NodeRule
|
|
53
|
-
from telegrinder.bot.rules.regex import Regex
|
|
54
|
-
from telegrinder.bot.rules.rule_enum import RuleEnum
|
|
55
|
-
from telegrinder.bot.rules.start import StartCommand
|
|
56
|
-
from telegrinder.bot.rules.state import State, StateMeta
|
|
57
|
-
from telegrinder.bot.rules.text import HasText, Text
|
|
58
|
-
from telegrinder.bot.rules.update import IsUpdateType
|
|
59
|
-
|
|
60
|
-
__all__ = (
|
|
1
|
+
from telegrinder.bot.rules.abc import ABCRule, AndRule, NotRule, OrRule
|
|
2
|
+
from telegrinder.bot.rules.callback_data import (
|
|
3
|
+
CallbackDataEq,
|
|
4
|
+
CallbackDataJsonEq,
|
|
5
|
+
CallbackDataJsonModel,
|
|
6
|
+
CallbackDataMap,
|
|
7
|
+
CallbackDataMarkup,
|
|
8
|
+
CallbackQueryDataRule,
|
|
9
|
+
CallbackQueryRule,
|
|
10
|
+
HasData,
|
|
11
|
+
)
|
|
12
|
+
from telegrinder.bot.rules.chat_join import (
|
|
13
|
+
ChatJoinRequestRule,
|
|
14
|
+
HasInviteLink,
|
|
15
|
+
InviteLinkByCreator,
|
|
16
|
+
InviteLinkName,
|
|
17
|
+
)
|
|
18
|
+
from telegrinder.bot.rules.command import Argument, Command
|
|
19
|
+
from telegrinder.bot.rules.enum_text import EnumTextRule
|
|
20
|
+
from telegrinder.bot.rules.func import FuncRule
|
|
21
|
+
from telegrinder.bot.rules.fuzzy import FuzzyText
|
|
22
|
+
from telegrinder.bot.rules.inline import (
|
|
23
|
+
HasLocation,
|
|
24
|
+
InlineQueryChatType,
|
|
25
|
+
InlineQueryMarkup,
|
|
26
|
+
InlineQueryRule,
|
|
27
|
+
InlineQueryText,
|
|
28
|
+
)
|
|
29
|
+
from telegrinder.bot.rules.integer import IntegerInRange, IsInteger
|
|
30
|
+
from telegrinder.bot.rules.is_from import (
|
|
31
|
+
IsBot,
|
|
32
|
+
IsChat,
|
|
33
|
+
IsChatId,
|
|
34
|
+
IsDice,
|
|
35
|
+
IsDiceEmoji,
|
|
36
|
+
IsForum,
|
|
37
|
+
IsForward,
|
|
38
|
+
IsForwardType,
|
|
39
|
+
IsGroup,
|
|
40
|
+
IsLanguageCode,
|
|
41
|
+
IsPremium,
|
|
42
|
+
IsPrivate,
|
|
43
|
+
IsReply,
|
|
44
|
+
IsSuperGroup,
|
|
45
|
+
IsUser,
|
|
46
|
+
IsUserId,
|
|
47
|
+
)
|
|
48
|
+
from telegrinder.bot.rules.markup import Markup
|
|
49
|
+
from telegrinder.bot.rules.mention import HasMention
|
|
50
|
+
from telegrinder.bot.rules.message import MessageRule
|
|
51
|
+
from telegrinder.bot.rules.message_entities import HasEntities, MessageEntities
|
|
52
|
+
from telegrinder.bot.rules.node import NodeRule
|
|
53
|
+
from telegrinder.bot.rules.regex import Regex
|
|
54
|
+
from telegrinder.bot.rules.rule_enum import RuleEnum
|
|
55
|
+
from telegrinder.bot.rules.start import StartCommand
|
|
56
|
+
from telegrinder.bot.rules.state import State, StateMeta
|
|
57
|
+
from telegrinder.bot.rules.text import HasText, Text
|
|
58
|
+
from telegrinder.bot.rules.update import IsUpdateType
|
|
59
|
+
|
|
60
|
+
__all__ = (
|
|
61
61
|
"ABCRule",
|
|
62
62
|
"AndRule",
|
|
63
63
|
"Argument",
|
|
@@ -115,5 +115,5 @@ __all__ = (
|
|
|
115
115
|
"StartCommand",
|
|
116
116
|
"State",
|
|
117
117
|
"StateMeta",
|
|
118
|
-
"Text",
|
|
119
|
-
)
|
|
118
|
+
"Text",
|
|
119
|
+
)
|