telegrinder 1.0.0rc1__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.
- telegrinder/__init__.py +258 -0
- telegrinder/__meta__.py +1 -0
- telegrinder/api/__init__.py +15 -0
- telegrinder/api/api.py +175 -0
- telegrinder/api/error.py +50 -0
- telegrinder/api/response.py +23 -0
- telegrinder/api/token.py +30 -0
- telegrinder/api/validators.py +30 -0
- telegrinder/bot/__init__.py +144 -0
- telegrinder/bot/bot.py +70 -0
- telegrinder/bot/cute_types/__init__.py +41 -0
- telegrinder/bot/cute_types/base.py +228 -0
- telegrinder/bot/cute_types/base.pyi +49 -0
- telegrinder/bot/cute_types/business_connection.py +9 -0
- telegrinder/bot/cute_types/business_messages_deleted.py +9 -0
- telegrinder/bot/cute_types/callback_query.py +248 -0
- telegrinder/bot/cute_types/chat_boost_removed.py +9 -0
- telegrinder/bot/cute_types/chat_boost_updated.py +9 -0
- telegrinder/bot/cute_types/chat_join_request.py +59 -0
- telegrinder/bot/cute_types/chat_member_updated.py +158 -0
- telegrinder/bot/cute_types/chosen_inline_result.py +11 -0
- telegrinder/bot/cute_types/inline_query.py +41 -0
- telegrinder/bot/cute_types/message.py +2809 -0
- telegrinder/bot/cute_types/message_reaction_count_updated.py +9 -0
- telegrinder/bot/cute_types/message_reaction_updated.py +9 -0
- telegrinder/bot/cute_types/paid_media_purchased.py +11 -0
- telegrinder/bot/cute_types/poll.py +9 -0
- telegrinder/bot/cute_types/poll_answer.py +9 -0
- telegrinder/bot/cute_types/pre_checkout_query.py +36 -0
- telegrinder/bot/cute_types/shipping_query.py +11 -0
- telegrinder/bot/cute_types/update.py +209 -0
- telegrinder/bot/cute_types/utils.py +141 -0
- telegrinder/bot/dispatch/__init__.py +99 -0
- telegrinder/bot/dispatch/abc.py +74 -0
- telegrinder/bot/dispatch/action.py +99 -0
- telegrinder/bot/dispatch/context.py +162 -0
- telegrinder/bot/dispatch/dispatch.py +362 -0
- telegrinder/bot/dispatch/handler/__init__.py +23 -0
- telegrinder/bot/dispatch/handler/abc.py +25 -0
- telegrinder/bot/dispatch/handler/audio_reply.py +43 -0
- telegrinder/bot/dispatch/handler/base.py +34 -0
- telegrinder/bot/dispatch/handler/document_reply.py +43 -0
- telegrinder/bot/dispatch/handler/func.py +73 -0
- telegrinder/bot/dispatch/handler/media_group_reply.py +43 -0
- telegrinder/bot/dispatch/handler/message_reply.py +35 -0
- telegrinder/bot/dispatch/handler/photo_reply.py +43 -0
- telegrinder/bot/dispatch/handler/sticker_reply.py +36 -0
- telegrinder/bot/dispatch/handler/video_reply.py +43 -0
- telegrinder/bot/dispatch/middleware/__init__.py +13 -0
- telegrinder/bot/dispatch/middleware/abc.py +112 -0
- telegrinder/bot/dispatch/middleware/box.py +32 -0
- telegrinder/bot/dispatch/middleware/filter.py +88 -0
- telegrinder/bot/dispatch/middleware/media_group.py +69 -0
- telegrinder/bot/dispatch/process.py +93 -0
- telegrinder/bot/dispatch/return_manager/__init__.py +21 -0
- telegrinder/bot/dispatch/return_manager/abc.py +107 -0
- telegrinder/bot/dispatch/return_manager/callback_query.py +19 -0
- telegrinder/bot/dispatch/return_manager/inline_query.py +14 -0
- telegrinder/bot/dispatch/return_manager/message.py +34 -0
- telegrinder/bot/dispatch/return_manager/pre_checkout_query.py +19 -0
- telegrinder/bot/dispatch/return_manager/utils.py +20 -0
- telegrinder/bot/dispatch/router/__init__.py +4 -0
- telegrinder/bot/dispatch/router/abc.py +15 -0
- telegrinder/bot/dispatch/router/base.py +154 -0
- telegrinder/bot/dispatch/view/__init__.py +15 -0
- telegrinder/bot/dispatch/view/abc.py +15 -0
- telegrinder/bot/dispatch/view/base.py +226 -0
- telegrinder/bot/dispatch/view/box.py +207 -0
- telegrinder/bot/dispatch/view/media_group.py +25 -0
- telegrinder/bot/dispatch/waiter_machine/__init__.py +25 -0
- telegrinder/bot/dispatch/waiter_machine/actions.py +16 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/__init__.py +13 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/callback.py +53 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/hasher.py +61 -0
- telegrinder/bot/dispatch/waiter_machine/hasher/message.py +49 -0
- telegrinder/bot/dispatch/waiter_machine/machine.py +264 -0
- telegrinder/bot/dispatch/waiter_machine/middleware.py +77 -0
- telegrinder/bot/dispatch/waiter_machine/short_state.py +105 -0
- telegrinder/bot/polling/__init__.py +4 -0
- telegrinder/bot/polling/abc.py +25 -0
- telegrinder/bot/polling/error_handler.py +93 -0
- telegrinder/bot/polling/polling.py +167 -0
- telegrinder/bot/polling/utils.py +12 -0
- telegrinder/bot/rules/__init__.py +166 -0
- telegrinder/bot/rules/abc.py +150 -0
- telegrinder/bot/rules/button.py +20 -0
- telegrinder/bot/rules/callback_data.py +109 -0
- telegrinder/bot/rules/chat_join.py +28 -0
- telegrinder/bot/rules/chat_member_updated.py +145 -0
- telegrinder/bot/rules/command.py +137 -0
- telegrinder/bot/rules/enum_text.py +29 -0
- telegrinder/bot/rules/func.py +21 -0
- telegrinder/bot/rules/fuzzy.py +21 -0
- telegrinder/bot/rules/inline.py +45 -0
- telegrinder/bot/rules/integer.py +19 -0
- telegrinder/bot/rules/is_from.py +213 -0
- telegrinder/bot/rules/logic.py +22 -0
- telegrinder/bot/rules/magic.py +60 -0
- telegrinder/bot/rules/markup.py +51 -0
- telegrinder/bot/rules/media.py +13 -0
- telegrinder/bot/rules/mention.py +15 -0
- telegrinder/bot/rules/message_entities.py +37 -0
- telegrinder/bot/rules/node.py +43 -0
- telegrinder/bot/rules/payload.py +89 -0
- telegrinder/bot/rules/payment_invoice.py +14 -0
- telegrinder/bot/rules/regex.py +34 -0
- telegrinder/bot/rules/rule_enum.py +71 -0
- telegrinder/bot/rules/start.py +73 -0
- telegrinder/bot/rules/state.py +35 -0
- telegrinder/bot/rules/text.py +27 -0
- telegrinder/bot/rules/update.py +14 -0
- telegrinder/bot/scenario/__init__.py +5 -0
- telegrinder/bot/scenario/abc.py +16 -0
- telegrinder/bot/scenario/checkbox.py +183 -0
- telegrinder/bot/scenario/choice.py +44 -0
- telegrinder/client/__init__.py +11 -0
- telegrinder/client/abc.py +136 -0
- telegrinder/client/form_data.py +34 -0
- telegrinder/client/rnet.py +198 -0
- telegrinder/model.py +133 -0
- telegrinder/model.pyi +57 -0
- telegrinder/modules.py +1081 -0
- telegrinder/msgspec_utils/__init__.py +42 -0
- telegrinder/msgspec_utils/abc.py +16 -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 +61 -0
- telegrinder/msgspec_utils/custom_types/literal.py +25 -0
- telegrinder/msgspec_utils/custom_types/option.py +17 -0
- telegrinder/msgspec_utils/decoder.py +388 -0
- telegrinder/msgspec_utils/encoder.py +204 -0
- telegrinder/msgspec_utils/json.py +15 -0
- telegrinder/msgspec_utils/tools.py +80 -0
- telegrinder/node/__init__.py +80 -0
- telegrinder/node/compose.py +193 -0
- telegrinder/node/nodes/__init__.py +96 -0
- telegrinder/node/nodes/attachment.py +169 -0
- telegrinder/node/nodes/callback_query.py +25 -0
- telegrinder/node/nodes/channel.py +97 -0
- telegrinder/node/nodes/command.py +33 -0
- telegrinder/node/nodes/error.py +43 -0
- telegrinder/node/nodes/event.py +70 -0
- telegrinder/node/nodes/file.py +39 -0
- telegrinder/node/nodes/global_node.py +66 -0
- telegrinder/node/nodes/i18n.py +110 -0
- telegrinder/node/nodes/me.py +26 -0
- telegrinder/node/nodes/message_entities.py +15 -0
- telegrinder/node/nodes/payload.py +84 -0
- telegrinder/node/nodes/reply_message.py +14 -0
- telegrinder/node/nodes/source.py +172 -0
- telegrinder/node/nodes/state_mutator.py +71 -0
- telegrinder/node/nodes/text.py +62 -0
- telegrinder/node/scope.py +88 -0
- telegrinder/node/utils.py +38 -0
- telegrinder/py.typed +0 -0
- telegrinder/rules.py +1 -0
- telegrinder/tools/__init__.py +183 -0
- telegrinder/tools/aio.py +147 -0
- telegrinder/tools/final.py +21 -0
- telegrinder/tools/formatting/__init__.py +85 -0
- telegrinder/tools/formatting/deep_links/__init__.py +39 -0
- telegrinder/tools/formatting/deep_links/links.py +468 -0
- telegrinder/tools/formatting/deep_links/parsing.py +88 -0
- telegrinder/tools/formatting/deep_links/validators.py +8 -0
- telegrinder/tools/formatting/html.py +241 -0
- telegrinder/tools/fullname.py +82 -0
- telegrinder/tools/global_context/__init__.py +13 -0
- telegrinder/tools/global_context/abc.py +63 -0
- telegrinder/tools/global_context/builtin_context.py +45 -0
- telegrinder/tools/global_context/global_context.py +614 -0
- telegrinder/tools/input_file_directory.py +30 -0
- telegrinder/tools/keyboard/__init__.py +6 -0
- telegrinder/tools/keyboard/abc.py +84 -0
- telegrinder/tools/keyboard/base.py +108 -0
- telegrinder/tools/keyboard/button.py +181 -0
- telegrinder/tools/keyboard/data.py +31 -0
- telegrinder/tools/keyboard/keyboard.py +160 -0
- telegrinder/tools/keyboard/utils.py +95 -0
- telegrinder/tools/lifespan.py +188 -0
- telegrinder/tools/limited_dict.py +35 -0
- telegrinder/tools/loop_wrapper.py +271 -0
- telegrinder/tools/magic/__init__.py +29 -0
- telegrinder/tools/magic/annotations.py +172 -0
- telegrinder/tools/magic/descriptors.py +57 -0
- telegrinder/tools/magic/function.py +254 -0
- telegrinder/tools/magic/inspect.py +16 -0
- telegrinder/tools/magic/shortcut.py +107 -0
- telegrinder/tools/member_descriptor_proxy.py +95 -0
- telegrinder/tools/parse_mode.py +12 -0
- telegrinder/tools/serialization/__init__.py +5 -0
- telegrinder/tools/serialization/abc.py +34 -0
- telegrinder/tools/serialization/json_ser.py +60 -0
- telegrinder/tools/serialization/msgpack_ser.py +197 -0
- telegrinder/tools/serialization/utils.py +18 -0
- telegrinder/tools/singleton/__init__.py +4 -0
- telegrinder/tools/singleton/abc.py +14 -0
- telegrinder/tools/singleton/singleton.py +18 -0
- telegrinder/tools/state_mutator/__init__.py +4 -0
- telegrinder/tools/state_mutator/mutation.py +85 -0
- telegrinder/tools/state_storage/__init__.py +4 -0
- telegrinder/tools/state_storage/abc.py +38 -0
- telegrinder/tools/state_storage/memory.py +27 -0
- telegrinder/tools/strings.py +22 -0
- telegrinder/types/__init__.py +323 -0
- telegrinder/types/enums.py +754 -0
- telegrinder/types/input_file.py +51 -0
- telegrinder/types/methods.py +6143 -0
- telegrinder/types/methods_utils.py +66 -0
- telegrinder/types/objects.py +8184 -0
- telegrinder/types/webapp.py +129 -0
- telegrinder/verification_utils.py +35 -0
- telegrinder-1.0.0rc1.dist-info/METADATA +166 -0
- telegrinder-1.0.0rc1.dist-info/RECORD +215 -0
- telegrinder-1.0.0rc1.dist-info/WHEEL +4 -0
- telegrinder-1.0.0rc1.dist-info/licenses/LICENSE +22 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
from collections import deque
|
|
3
|
+
|
|
4
|
+
from kungfu import Error, Ok, Pulse, Result
|
|
5
|
+
|
|
6
|
+
from telegrinder.api.api import API
|
|
7
|
+
from telegrinder.bot.dispatch.context import Context
|
|
8
|
+
from telegrinder.bot.dispatch.handler.abc import ABCHandler
|
|
9
|
+
from telegrinder.bot.dispatch.handler.func import FuncHandler, Function
|
|
10
|
+
from telegrinder.bot.dispatch.middleware.abc import ABCMiddleware
|
|
11
|
+
from telegrinder.bot.dispatch.process import check_rule, process_inner
|
|
12
|
+
from telegrinder.bot.dispatch.return_manager.abc import ABCReturnManager
|
|
13
|
+
from telegrinder.bot.dispatch.view.abc import ABCView
|
|
14
|
+
from telegrinder.bot.rules.abc import ABCRule, Always
|
|
15
|
+
from telegrinder.types.enums import UpdateType
|
|
16
|
+
from telegrinder.types.objects import (
|
|
17
|
+
BusinessConnection,
|
|
18
|
+
BusinessMessagesDeleted,
|
|
19
|
+
CallbackQuery,
|
|
20
|
+
ChatBoostRemoved,
|
|
21
|
+
ChatBoostUpdated,
|
|
22
|
+
ChatJoinRequest,
|
|
23
|
+
ChatMemberUpdated,
|
|
24
|
+
ChosenInlineResult,
|
|
25
|
+
InlineQuery,
|
|
26
|
+
Message,
|
|
27
|
+
MessageReactionCountUpdated,
|
|
28
|
+
MessageReactionUpdated,
|
|
29
|
+
PaidMediaPurchased,
|
|
30
|
+
Poll,
|
|
31
|
+
PollAnswer,
|
|
32
|
+
PreCheckoutQuery,
|
|
33
|
+
ShippingQuery,
|
|
34
|
+
Update,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
if typing.TYPE_CHECKING:
|
|
38
|
+
from nodnod.agent.base import Agent
|
|
39
|
+
|
|
40
|
+
type UpdateModel = typing.Union[
|
|
41
|
+
BusinessConnection,
|
|
42
|
+
BusinessMessagesDeleted,
|
|
43
|
+
CallbackQuery,
|
|
44
|
+
ChatBoostRemoved,
|
|
45
|
+
ChatBoostUpdated,
|
|
46
|
+
ChatJoinRequest,
|
|
47
|
+
ChatMemberUpdated,
|
|
48
|
+
ChosenInlineResult,
|
|
49
|
+
InlineQuery,
|
|
50
|
+
Message,
|
|
51
|
+
MessageReactionCountUpdated,
|
|
52
|
+
MessageReactionUpdated,
|
|
53
|
+
PaidMediaPurchased,
|
|
54
|
+
Poll,
|
|
55
|
+
PollAnswer,
|
|
56
|
+
PreCheckoutQuery,
|
|
57
|
+
ShippingQuery,
|
|
58
|
+
]
|
|
59
|
+
type ViewResult = Result[str, str] | Result[str, Exception]
|
|
60
|
+
|
|
61
|
+
OK_CHECK: typing.Final = Ok()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class View(ABCView):
|
|
65
|
+
filter: ABCRule
|
|
66
|
+
handlers: deque[ABCHandler]
|
|
67
|
+
middlewares: deque[ABCMiddleware]
|
|
68
|
+
return_manager: ABCReturnManager | None
|
|
69
|
+
|
|
70
|
+
def __init__(
|
|
71
|
+
self,
|
|
72
|
+
*,
|
|
73
|
+
agent_cls: type[Agent] | None = None,
|
|
74
|
+
return_manager: ABCReturnManager | None = None,
|
|
75
|
+
) -> None:
|
|
76
|
+
self.filter = Always()
|
|
77
|
+
self.handlers = deque()
|
|
78
|
+
self.middlewares = deque()
|
|
79
|
+
self.agent_cls = agent_cls
|
|
80
|
+
self.return_manager = return_manager
|
|
81
|
+
|
|
82
|
+
def __bool__(self) -> bool:
|
|
83
|
+
return bool(self.handlers) or bool(self.middlewares)
|
|
84
|
+
|
|
85
|
+
def __repr__(self) -> str:
|
|
86
|
+
return "<{}>".format(type(self).__name__)
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def auto_rules(self) -> ABCRule:
|
|
90
|
+
return self.filter
|
|
91
|
+
|
|
92
|
+
@auto_rules.setter
|
|
93
|
+
def auto_rules(self, value: ABCRule | typing.Iterable[ABCRule], /) -> None:
|
|
94
|
+
for rule in (value,) if isinstance(value, ABCRule) else value:
|
|
95
|
+
self.filter &= rule
|
|
96
|
+
|
|
97
|
+
def __call__[T: Function](
|
|
98
|
+
self,
|
|
99
|
+
*rules: ABCRule,
|
|
100
|
+
final: bool = True,
|
|
101
|
+
agent: type[Agent] | None = None,
|
|
102
|
+
) -> typing.Callable[[T], T]:
|
|
103
|
+
def decorator(function: T, /) -> T:
|
|
104
|
+
self.handlers.append(
|
|
105
|
+
FuncHandler(
|
|
106
|
+
function=function,
|
|
107
|
+
rules=rules,
|
|
108
|
+
agent=agent or self.agent_cls,
|
|
109
|
+
final=final,
|
|
110
|
+
),
|
|
111
|
+
)
|
|
112
|
+
return function
|
|
113
|
+
|
|
114
|
+
return decorator
|
|
115
|
+
|
|
116
|
+
@typing.overload
|
|
117
|
+
def register_middleware[T: ABCMiddleware](self, middleware_cls: type[T], /) -> type[T]: ...
|
|
118
|
+
|
|
119
|
+
@typing.overload
|
|
120
|
+
def register_middleware(self, middleware: ABCMiddleware, /) -> None: ...
|
|
121
|
+
|
|
122
|
+
def register_middleware(
|
|
123
|
+
self,
|
|
124
|
+
middleware: type[ABCMiddleware] | ABCMiddleware,
|
|
125
|
+
) -> typing.Callable[..., typing.Any] | None:
|
|
126
|
+
self.middlewares.append(middleware() if isinstance(middleware, type) else middleware)
|
|
127
|
+
return middleware if isinstance(middleware, type) else None
|
|
128
|
+
|
|
129
|
+
def load(self, external: typing.Self, /) -> None:
|
|
130
|
+
if not external:
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
self.handlers.extend(external.handlers)
|
|
134
|
+
self.middlewares.extend(external.middlewares)
|
|
135
|
+
|
|
136
|
+
if not isinstance(external.filter, Always):
|
|
137
|
+
self.filter &= external.filter
|
|
138
|
+
|
|
139
|
+
if external.return_manager is not None and self.return_manager is None:
|
|
140
|
+
self.return_manager = external.return_manager
|
|
141
|
+
|
|
142
|
+
elif self.return_manager is not None and external.return_manager is not None:
|
|
143
|
+
self.return_manager.managers.extend(external.return_manager.managers)
|
|
144
|
+
|
|
145
|
+
async def check(self, api: API, update: Update, context: Context) -> Pulse[str]:
|
|
146
|
+
if not bool(self):
|
|
147
|
+
return Error("View is empty.")
|
|
148
|
+
|
|
149
|
+
if not await check_rule(self.filter, context):
|
|
150
|
+
return Error("Filter is failed.")
|
|
151
|
+
|
|
152
|
+
return OK_CHECK
|
|
153
|
+
|
|
154
|
+
async def process(self, api: API, update: Update, context: Context) -> ViewResult:
|
|
155
|
+
return await process_inner(
|
|
156
|
+
api,
|
|
157
|
+
update,
|
|
158
|
+
context,
|
|
159
|
+
self,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class EventView(View):
|
|
164
|
+
def __init__(
|
|
165
|
+
self,
|
|
166
|
+
update_type: UpdateType,
|
|
167
|
+
return_manager: ABCReturnManager | None = None,
|
|
168
|
+
agent_cls: type[Agent] | None = None,
|
|
169
|
+
) -> None:
|
|
170
|
+
super().__init__(
|
|
171
|
+
agent_cls=agent_cls,
|
|
172
|
+
return_manager=return_manager,
|
|
173
|
+
)
|
|
174
|
+
self.update_type = update_type
|
|
175
|
+
|
|
176
|
+
def __repr__(self) -> str:
|
|
177
|
+
return "<{}: {!r}>".format(type(self).__name__, self.update_type)
|
|
178
|
+
|
|
179
|
+
async def check(self, api: API, update: Update, context: Context) -> Pulse[str]:
|
|
180
|
+
# If update is not of the expected, instantly skip checking the view
|
|
181
|
+
if update.update_type != self.update_type:
|
|
182
|
+
return Error(f"Incoming event `{update.update_type!r}` is not `{self.update_type!r}`.")
|
|
183
|
+
return await super().check(api, update, context)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class EventModelView[T: (UpdateModel)](View):
|
|
187
|
+
def __init__(
|
|
188
|
+
self,
|
|
189
|
+
model: type[T],
|
|
190
|
+
return_manager: ABCReturnManager | None = None,
|
|
191
|
+
agent_cls: type[Agent] | None = None,
|
|
192
|
+
) -> None:
|
|
193
|
+
super().__init__(
|
|
194
|
+
agent_cls=agent_cls,
|
|
195
|
+
return_manager=return_manager,
|
|
196
|
+
)
|
|
197
|
+
self.model = model
|
|
198
|
+
|
|
199
|
+
def __repr__(self) -> str:
|
|
200
|
+
return "<{}: {}>".format(type(self).__name__, self.model.__name__)
|
|
201
|
+
|
|
202
|
+
async def check(self, api: API, update: Update, context: Context) -> Pulse[str]:
|
|
203
|
+
# If update object is not of the expected type of object, instantly skip checking the view
|
|
204
|
+
if update.incoming_update.__class__ is not self.model:
|
|
205
|
+
return Error(
|
|
206
|
+
f"Incoming event model `{update.incoming_update.__class__.__name__!r}`"
|
|
207
|
+
f" is not `{self.model.__name__!r}`.",
|
|
208
|
+
)
|
|
209
|
+
return await super().check(api, update, context)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class ErrorView(View):
|
|
213
|
+
async def process(self, api: API, update: Update, context: Context) -> ViewResult:
|
|
214
|
+
result = await super().process(api, update, context)
|
|
215
|
+
|
|
216
|
+
if not result and context.exception_update:
|
|
217
|
+
return Error(context.exception_update.unwrap())
|
|
218
|
+
|
|
219
|
+
return result
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class RawEventView(View):
|
|
223
|
+
pass
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
__all__ = ("ErrorView", "EventView", "RawEventView", "View")
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import typing
|
|
3
|
+
from functools import cached_property
|
|
4
|
+
from types import MappingProxyType
|
|
5
|
+
|
|
6
|
+
from telegrinder.bot.dispatch.return_manager.callback_query import CallbackQueryReturnManager
|
|
7
|
+
from telegrinder.bot.dispatch.return_manager.inline_query import InlineQueryReturnManager
|
|
8
|
+
from telegrinder.bot.dispatch.return_manager.message import MessageReturnManager
|
|
9
|
+
from telegrinder.bot.dispatch.return_manager.pre_checkout_query import PreCheckoutQueryReturnManager
|
|
10
|
+
from telegrinder.bot.dispatch.view.base import (
|
|
11
|
+
ErrorView,
|
|
12
|
+
EventView,
|
|
13
|
+
RawEventView,
|
|
14
|
+
View,
|
|
15
|
+
)
|
|
16
|
+
from telegrinder.bot.dispatch.view.media_group import MediaGroupView
|
|
17
|
+
from telegrinder.types.enums import UpdateType
|
|
18
|
+
|
|
19
|
+
if typing.TYPE_CHECKING:
|
|
20
|
+
from telegrinder.bot.dispatch.return_manager.abc import ABCReturnManager
|
|
21
|
+
|
|
22
|
+
EXCLUDE_VIEW_META: typing.Final = dict(exclude_view=True)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def event_view[T: EventView](
|
|
26
|
+
update_type: UpdateType,
|
|
27
|
+
return_manager: ABCReturnManager | None = None,
|
|
28
|
+
/,
|
|
29
|
+
) -> typing.Callable[[], T]:
|
|
30
|
+
def factory() -> T:
|
|
31
|
+
return typing.cast("T", EventView(update_type, return_manager))
|
|
32
|
+
|
|
33
|
+
return factory
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def view[T: View](
|
|
37
|
+
view_class: type[View],
|
|
38
|
+
return_manager: ABCReturnManager | None = None,
|
|
39
|
+
/,
|
|
40
|
+
) -> typing.Callable[[], T]:
|
|
41
|
+
def factory() -> T:
|
|
42
|
+
return typing.cast("T", view_class(return_manager=return_manager))
|
|
43
|
+
|
|
44
|
+
return factory
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
event_model_view = view
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclasses.dataclass(kw_only=True)
|
|
51
|
+
class EventViewBox[
|
|
52
|
+
MessageView: EventView = EventView,
|
|
53
|
+
EditedMessageView: EventView = EventView,
|
|
54
|
+
ChannelPostView: EventView = EventView,
|
|
55
|
+
EditedChannelPostView: EventView = EventView,
|
|
56
|
+
BusinessConnectionView: EventView = EventView,
|
|
57
|
+
BusinessMessageView: EventView = EventView,
|
|
58
|
+
EditedBusinessMessageView: EventView = EventView,
|
|
59
|
+
DeletedBusinessMessagesView: EventView = EventView,
|
|
60
|
+
MessageReactionView: EventView = EventView,
|
|
61
|
+
MessageReactionCountView: EventView = EventView,
|
|
62
|
+
InlineQueryView: EventView = EventView,
|
|
63
|
+
ChosenInlineResultView: EventView = EventView,
|
|
64
|
+
CallbackQueryView: EventView = EventView,
|
|
65
|
+
ShippingQueryView: EventView = EventView,
|
|
66
|
+
PreCheckoutQueryView: EventView = EventView,
|
|
67
|
+
PurchasedPaidMediaView: EventView = EventView,
|
|
68
|
+
PollView: EventView = EventView,
|
|
69
|
+
PollAnswerView: EventView = EventView,
|
|
70
|
+
MyChatMemberView: EventView = EventView,
|
|
71
|
+
ChatMemberView: EventView = EventView,
|
|
72
|
+
ChatJoinRequestView: EventView = EventView,
|
|
73
|
+
ChatBoostView: EventView = EventView,
|
|
74
|
+
RemovedChatBoostView: EventView = EventView,
|
|
75
|
+
]:
|
|
76
|
+
message: MessageView = dataclasses.field(default_factory=event_view(UpdateType.MESSAGE, MessageReturnManager()))
|
|
77
|
+
edited_message: EditedMessageView = dataclasses.field(
|
|
78
|
+
default_factory=event_view(UpdateType.EDITED_MESSAGE, MessageReturnManager()),
|
|
79
|
+
)
|
|
80
|
+
channel_post: ChannelPostView = dataclasses.field(
|
|
81
|
+
default_factory=event_view(UpdateType.CHANNEL_POST, MessageReturnManager()),
|
|
82
|
+
)
|
|
83
|
+
edited_channel_post: EditedChannelPostView = dataclasses.field(
|
|
84
|
+
default_factory=event_view(UpdateType.EDITED_CHANNEL_POST, MessageReturnManager()),
|
|
85
|
+
)
|
|
86
|
+
business_connection: BusinessConnectionView = dataclasses.field(
|
|
87
|
+
default_factory=event_view(UpdateType.BUSINESS_CONNECTION),
|
|
88
|
+
)
|
|
89
|
+
business_message: BusinessMessageView = dataclasses.field(
|
|
90
|
+
default_factory=event_view(UpdateType.BUSINESS_MESSAGE, MessageReturnManager()),
|
|
91
|
+
)
|
|
92
|
+
edited_business_message: EditedBusinessMessageView = dataclasses.field(
|
|
93
|
+
default_factory=event_view(UpdateType.EDITED_BUSINESS_MESSAGE, MessageReturnManager()),
|
|
94
|
+
)
|
|
95
|
+
deleted_business_messages: DeletedBusinessMessagesView = dataclasses.field(
|
|
96
|
+
default_factory=event_view(UpdateType.DELETED_BUSINESS_MESSAGES),
|
|
97
|
+
)
|
|
98
|
+
message_reaction: MessageReactionView = dataclasses.field(default_factory=event_view(UpdateType.MESSAGE_REACTION))
|
|
99
|
+
message_reaction_count: MessageReactionCountView = dataclasses.field(
|
|
100
|
+
default_factory=event_view(UpdateType.MESSAGE_REACTION_COUNT),
|
|
101
|
+
)
|
|
102
|
+
inline_query: InlineQueryView = dataclasses.field(
|
|
103
|
+
default_factory=event_view(UpdateType.INLINE_QUERY, InlineQueryReturnManager()),
|
|
104
|
+
)
|
|
105
|
+
chosen_inline_result: ChosenInlineResultView = dataclasses.field(
|
|
106
|
+
default_factory=event_view(UpdateType.CHOSEN_INLINE_RESULT),
|
|
107
|
+
)
|
|
108
|
+
callback_query: CallbackQueryView = dataclasses.field(
|
|
109
|
+
default_factory=event_view(UpdateType.CALLBACK_QUERY, CallbackQueryReturnManager()),
|
|
110
|
+
)
|
|
111
|
+
shipping_query: ShippingQueryView = dataclasses.field(default_factory=event_view(UpdateType.SHIPPING_QUERY))
|
|
112
|
+
pre_checkout_query: PreCheckoutQueryView = dataclasses.field(
|
|
113
|
+
default_factory=event_view(UpdateType.PRE_CHECKOUT_QUERY, PreCheckoutQueryReturnManager()),
|
|
114
|
+
)
|
|
115
|
+
purchased_paid_media: PurchasedPaidMediaView = dataclasses.field(
|
|
116
|
+
default_factory=event_view(UpdateType.PURCHASED_PAID_MEDIA),
|
|
117
|
+
)
|
|
118
|
+
poll: PollView = dataclasses.field(default_factory=event_view(UpdateType.POLL))
|
|
119
|
+
poll_answer: PollAnswerView = dataclasses.field(default_factory=event_view(UpdateType.POLL_ANSWER))
|
|
120
|
+
my_chat_member: MyChatMemberView = dataclasses.field(default_factory=event_view(UpdateType.MY_CHAT_MEMBER))
|
|
121
|
+
chat_member: ChatMemberView = dataclasses.field(default_factory=event_view(UpdateType.CHAT_MEMBER))
|
|
122
|
+
chat_join_request: ChatJoinRequestView = dataclasses.field(default_factory=event_view(UpdateType.CHAT_JOIN_REQUEST))
|
|
123
|
+
chat_boost: ChatBoostView = dataclasses.field(default_factory=event_view(UpdateType.CHAT_BOOST))
|
|
124
|
+
removed_chat_boost: RemovedChatBoostView = dataclasses.field(
|
|
125
|
+
default_factory=event_view(UpdateType.REMOVED_CHAT_BOOST),
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@dataclasses.dataclass(kw_only=True)
|
|
130
|
+
class EventModelViewBox[MediaGroup: View = MediaGroupView]:
|
|
131
|
+
media_group: MediaGroup = dataclasses.field(
|
|
132
|
+
default_factory=event_model_view(MediaGroupView, MessageReturnManager())
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@dataclasses.dataclass(kw_only=True)
|
|
137
|
+
class ViewBox[
|
|
138
|
+
MessageView: EventView = EventView,
|
|
139
|
+
EditedMessageView: EventView = EventView,
|
|
140
|
+
ChannelPostView: EventView = EventView,
|
|
141
|
+
EditedChannelPostView: EventView = EventView,
|
|
142
|
+
BusinessConnectionView: EventView = EventView,
|
|
143
|
+
BusinessMessageView: EventView = EventView,
|
|
144
|
+
EditedBusinessMessageView: EventView = EventView,
|
|
145
|
+
DeletedBusinessMessagesView: EventView = EventView,
|
|
146
|
+
MessageReactionView: EventView = EventView,
|
|
147
|
+
MessageReactionCountView: EventView = EventView,
|
|
148
|
+
InlineQueryView: EventView = EventView,
|
|
149
|
+
ChosenInlineResultView: EventView = EventView,
|
|
150
|
+
CallbackQueryView: EventView = EventView,
|
|
151
|
+
ShippingQueryView: EventView = EventView,
|
|
152
|
+
PreCheckoutQueryView: EventView = EventView,
|
|
153
|
+
PurchasedPaidMediaView: EventView = EventView,
|
|
154
|
+
PollView: EventView = EventView,
|
|
155
|
+
PollAnswerView: EventView = EventView,
|
|
156
|
+
MyChatMemberView: EventView = EventView,
|
|
157
|
+
ChatMemberView: EventView = EventView,
|
|
158
|
+
ChatJoinRequestView: EventView = EventView,
|
|
159
|
+
ChatBoostView: EventView = EventView,
|
|
160
|
+
RemovedChatBoostView: EventView = EventView,
|
|
161
|
+
MediaGroup: View = MediaGroupView,
|
|
162
|
+
Error: ErrorView = ErrorView,
|
|
163
|
+
RawEvent: RawEventView = RawEventView,
|
|
164
|
+
](
|
|
165
|
+
EventModelViewBox[MediaGroup],
|
|
166
|
+
EventViewBox[
|
|
167
|
+
MessageView,
|
|
168
|
+
EditedMessageView,
|
|
169
|
+
ChannelPostView,
|
|
170
|
+
EditedChannelPostView,
|
|
171
|
+
BusinessConnectionView,
|
|
172
|
+
BusinessMessageView,
|
|
173
|
+
EditedBusinessMessageView,
|
|
174
|
+
DeletedBusinessMessagesView,
|
|
175
|
+
MessageReactionView,
|
|
176
|
+
MessageReactionCountView,
|
|
177
|
+
InlineQueryView,
|
|
178
|
+
ChosenInlineResultView,
|
|
179
|
+
CallbackQueryView,
|
|
180
|
+
ShippingQueryView,
|
|
181
|
+
PreCheckoutQueryView,
|
|
182
|
+
PurchasedPaidMediaView,
|
|
183
|
+
PollView,
|
|
184
|
+
PollAnswerView,
|
|
185
|
+
MyChatMemberView,
|
|
186
|
+
ChatMemberView,
|
|
187
|
+
ChatJoinRequestView,
|
|
188
|
+
ChatBoostView,
|
|
189
|
+
RemovedChatBoostView,
|
|
190
|
+
],
|
|
191
|
+
):
|
|
192
|
+
event_error: Error = dataclasses.field(default_factory=view(ErrorView), metadata=EXCLUDE_VIEW_META)
|
|
193
|
+
raw: RawEvent = dataclasses.field(default_factory=view(RawEventView), metadata=EXCLUDE_VIEW_META)
|
|
194
|
+
|
|
195
|
+
@cached_property
|
|
196
|
+
def views(self) -> MappingProxyType[str, View]:
|
|
197
|
+
return MappingProxyType(
|
|
198
|
+
mapping={
|
|
199
|
+
field.name: obj
|
|
200
|
+
for field in dataclasses.fields(self)
|
|
201
|
+
if isinstance(obj := getattr(self, field.name), View)
|
|
202
|
+
and field.metadata.get("exclude_view", False) is False
|
|
203
|
+
},
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
__all__ = ("EventModelViewBox", "EventViewBox", "ViewBox")
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
from telegrinder.bot.dispatch.view.base import EventModelView
|
|
4
|
+
from telegrinder.bot.rules.media import IsMediaGroup
|
|
5
|
+
from telegrinder.types.objects import Message
|
|
6
|
+
|
|
7
|
+
if typing.TYPE_CHECKING:
|
|
8
|
+
from nodnod.agent.base import Agent
|
|
9
|
+
|
|
10
|
+
from telegrinder.bot.dispatch.return_manager.abc import ABCReturnManager
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MediaGroupView(EventModelView[Message]):
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
*,
|
|
17
|
+
return_manager: ABCReturnManager | None = None,
|
|
18
|
+
agent_cls: type[Agent] | None = None,
|
|
19
|
+
) -> None:
|
|
20
|
+
super().__init__(model=Message, return_manager=return_manager, agent_cls=agent_cls)
|
|
21
|
+
|
|
22
|
+
self.filter = IsMediaGroup()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = ("MediaGroupView",)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from telegrinder.bot.dispatch.waiter_machine.hasher import (
|
|
2
|
+
CALLBACK_QUERY_FOR_MESSAGE,
|
|
3
|
+
CALLBACK_QUERY_FROM_CHAT,
|
|
4
|
+
CALLBACK_QUERY_IN_CHAT_FOR_MESSAGE,
|
|
5
|
+
MESSAGE_FROM_USER,
|
|
6
|
+
MESSAGE_FROM_USER_IN_CHAT,
|
|
7
|
+
MESSAGE_IN_CHAT,
|
|
8
|
+
Hasher,
|
|
9
|
+
)
|
|
10
|
+
from telegrinder.bot.dispatch.waiter_machine.machine import WaiterMachine
|
|
11
|
+
from telegrinder.bot.dispatch.waiter_machine.middleware import WaiterMiddleware
|
|
12
|
+
from telegrinder.bot.dispatch.waiter_machine.short_state import ShortState
|
|
13
|
+
|
|
14
|
+
__all__ = (
|
|
15
|
+
"CALLBACK_QUERY_FOR_MESSAGE",
|
|
16
|
+
"CALLBACK_QUERY_FROM_CHAT",
|
|
17
|
+
"CALLBACK_QUERY_IN_CHAT_FOR_MESSAGE",
|
|
18
|
+
"MESSAGE_FROM_USER",
|
|
19
|
+
"MESSAGE_FROM_USER_IN_CHAT",
|
|
20
|
+
"MESSAGE_IN_CHAT",
|
|
21
|
+
"Hasher",
|
|
22
|
+
"ShortState",
|
|
23
|
+
"WaiterMachine",
|
|
24
|
+
"WaiterMiddleware",
|
|
25
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
from telegrinder.bot.dispatch.handler.abc import ABCHandler
|
|
4
|
+
|
|
5
|
+
if typing.TYPE_CHECKING:
|
|
6
|
+
from telegrinder.bot.cute_types.base import BaseCute
|
|
7
|
+
|
|
8
|
+
type OnDrop[Event: BaseCute[typing.Any] = typing.Any] = typing.Callable[..., typing.Awaitable[typing.Any] | typing.Any]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class WaiterActions[Event: BaseCute[typing.Any] = typing.Any](typing.TypedDict):
|
|
12
|
+
on_miss: typing.NotRequired[ABCHandler]
|
|
13
|
+
on_drop: typing.NotRequired[OnDrop[Event]]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
__all__ = ("WaiterActions",)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .callback import CALLBACK_QUERY_FOR_MESSAGE, CALLBACK_QUERY_FROM_CHAT, CALLBACK_QUERY_IN_CHAT_FOR_MESSAGE
|
|
2
|
+
from .hasher import Hasher
|
|
3
|
+
from .message import MESSAGE_FROM_USER, MESSAGE_FROM_USER_IN_CHAT, MESSAGE_IN_CHAT
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
"CALLBACK_QUERY_FOR_MESSAGE",
|
|
7
|
+
"CALLBACK_QUERY_FROM_CHAT",
|
|
8
|
+
"CALLBACK_QUERY_IN_CHAT_FOR_MESSAGE",
|
|
9
|
+
"MESSAGE_FROM_USER",
|
|
10
|
+
"MESSAGE_FROM_USER_IN_CHAT",
|
|
11
|
+
"MESSAGE_IN_CHAT",
|
|
12
|
+
"Hasher",
|
|
13
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from kungfu.library.monad.option import Some
|
|
2
|
+
|
|
3
|
+
from telegrinder.bot.cute_types.callback_query import CallbackQueryCute as CallbackQuery
|
|
4
|
+
from telegrinder.bot.dispatch.waiter_machine.hasher.hasher import Hasher
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def from_chat_hash(chat_id: int) -> int:
|
|
8
|
+
return chat_id
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_chat_from_event(event: CallbackQuery) -> int | None:
|
|
12
|
+
return event.chat.then(lambda chat: Some(chat.id)).unwrap_or_none()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def for_message_hash(message_id: int) -> int:
|
|
16
|
+
return message_id
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_message_for_event(event: CallbackQuery) -> int | None:
|
|
20
|
+
return event.message_id.unwrap_or_none()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def for_message_in_chat(chat_and_message: tuple[int, int]) -> str:
|
|
24
|
+
return f"{chat_and_message[0]}_{chat_and_message[1]}"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_chat_and_message_for_event(event: CallbackQuery) -> tuple[int, int] | None:
|
|
28
|
+
if not event.message_id or not event.chat:
|
|
29
|
+
return None
|
|
30
|
+
return event.chat.unwrap().id, event.message_id.unwrap()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
CALLBACK_QUERY_FROM_CHAT = Hasher(
|
|
34
|
+
get_hash_from_data=from_chat_hash,
|
|
35
|
+
get_data_from_event=get_chat_from_event,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
CALLBACK_QUERY_FOR_MESSAGE = Hasher(
|
|
39
|
+
get_hash_from_data=for_message_hash,
|
|
40
|
+
get_data_from_event=get_message_for_event,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
CALLBACK_QUERY_IN_CHAT_FOR_MESSAGE = Hasher(
|
|
44
|
+
get_hash_from_data=for_message_in_chat,
|
|
45
|
+
get_data_from_event=get_chat_and_message_for_event,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
__all__ = (
|
|
50
|
+
"CALLBACK_QUERY_FOR_MESSAGE",
|
|
51
|
+
"CALLBACK_QUERY_FROM_CHAT",
|
|
52
|
+
"CALLBACK_QUERY_IN_CHAT_FOR_MESSAGE",
|
|
53
|
+
)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import secrets
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
from kungfu.library.misc import from_optional
|
|
5
|
+
from kungfu.library.monad.option import Option
|
|
6
|
+
|
|
7
|
+
from telegrinder.bot.cute_types import BaseCute
|
|
8
|
+
from telegrinder.bot.dispatch.view.base import View
|
|
9
|
+
|
|
10
|
+
type HasherWithData[Event: BaseCute, Data] = tuple[Hasher[Event, Data], View, Data]
|
|
11
|
+
|
|
12
|
+
Event = typing.TypeVar("Event", bound=BaseCute, covariant=True)
|
|
13
|
+
Data = typing.TypeVar("Data", covariant=True)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def ECHO[T](__x: T) -> T: # noqa
|
|
17
|
+
return __x
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Hasher(typing.Generic[Event, Data]):
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
get_hash_from_data: typing.Callable[[Data], typing.Hashable | None] | None = None,
|
|
24
|
+
get_data_from_event: typing.Callable[[Event], Data | None] | None = None,
|
|
25
|
+
) -> None:
|
|
26
|
+
self.code = secrets.token_hex(8)
|
|
27
|
+
self._get_hash_from_data = get_hash_from_data
|
|
28
|
+
self._get_data_from_event = get_data_from_event
|
|
29
|
+
|
|
30
|
+
def __call__[D](
|
|
31
|
+
self: Hasher[Event, D],
|
|
32
|
+
view: View,
|
|
33
|
+
data: D,
|
|
34
|
+
/,
|
|
35
|
+
) -> HasherWithData[Event, D]:
|
|
36
|
+
return (self, view, data)
|
|
37
|
+
|
|
38
|
+
def __hash__(self) -> int:
|
|
39
|
+
return hash(self.code)
|
|
40
|
+
|
|
41
|
+
def __repr__(self) -> str:
|
|
42
|
+
return f"<Hasher {self.code}>"
|
|
43
|
+
|
|
44
|
+
def get_hash_from_data[D](self: Hasher[Event, D], data: D) -> Option[typing.Hashable]:
|
|
45
|
+
if self._get_hash_from_data is None:
|
|
46
|
+
raise NotImplementedError
|
|
47
|
+
return from_optional(self._get_hash_from_data(data))
|
|
48
|
+
|
|
49
|
+
def get_data_from_event[E: BaseCute](self: Hasher[E, Data], event: E) -> Option[Data]:
|
|
50
|
+
if not self._get_data_from_event:
|
|
51
|
+
raise NotImplementedError
|
|
52
|
+
return from_optional(self._get_data_from_event(event))
|
|
53
|
+
|
|
54
|
+
def get_hash_from_data_from_event[E: BaseCute](
|
|
55
|
+
self: Hasher[E, Data],
|
|
56
|
+
event: E,
|
|
57
|
+
) -> Option[typing.Hashable]:
|
|
58
|
+
return self.get_data_from_event(event).then(self.get_hash_from_data)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
__all__ = ("Hasher",)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from telegrinder.bot.cute_types.message import MessageCute as Message
|
|
2
|
+
from telegrinder.bot.dispatch.waiter_machine.hasher.hasher import Hasher
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def from_chat_hash(chat_id: int) -> int:
|
|
6
|
+
return chat_id
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_chat_from_event(event: Message) -> int:
|
|
10
|
+
return event.chat.id
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def from_user_in_chat_hash(chat_and_user: tuple[int, int]) -> str:
|
|
14
|
+
return f"{chat_and_user[0]}_{chat_and_user[1]}"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_user_in_chat_from_event(event: Message) -> tuple[int, int]:
|
|
18
|
+
return event.chat.id, event.from_user.id
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def from_user_hash(from_id: int) -> int:
|
|
22
|
+
return from_id
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_user_from_event(event: Message) -> int:
|
|
26
|
+
return event.from_user.id
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
MESSAGE_IN_CHAT = Hasher(
|
|
30
|
+
get_hash_from_data=from_chat_hash,
|
|
31
|
+
get_data_from_event=get_chat_from_event,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
MESSAGE_FROM_USER = Hasher(
|
|
35
|
+
get_hash_from_data=from_user_hash,
|
|
36
|
+
get_data_from_event=get_user_from_event,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
MESSAGE_FROM_USER_IN_CHAT = Hasher(
|
|
40
|
+
get_hash_from_data=from_user_in_chat_hash,
|
|
41
|
+
get_data_from_event=get_user_in_chat_from_event,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
__all__ = (
|
|
46
|
+
"MESSAGE_FROM_USER",
|
|
47
|
+
"MESSAGE_FROM_USER_IN_CHAT",
|
|
48
|
+
"MESSAGE_IN_CHAT",
|
|
49
|
+
)
|