aiogram-webhook 1.0.0__tar.gz → 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0}/PKG-INFO +55 -33
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0}/README.md +37 -16
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0}/pyproject.toml +10 -64
- aiogram_webhook-2.0.0/src/aiogram_webhook/__init__.py +21 -0
- aiogram_webhook-1.0.0/aiogram_webhook/adapters/aiohttp.py → aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/aiohttp/adapter.py +25 -20
- aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/aiohttp/mapping.py +15 -0
- aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/base_adapter.py +86 -0
- aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/base_mapping.py +38 -0
- aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/fastapi/adapter.py +49 -0
- aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/fastapi/mapping.py +15 -0
- aiogram_webhook-2.0.0/src/aiogram_webhook/config/__init__.py +0 -0
- aiogram_webhook-2.0.0/src/aiogram_webhook/config/bot.py +12 -0
- aiogram_webhook-2.0.0/src/aiogram_webhook/config/webhook.py +19 -0
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/engines/base.py +43 -28
- aiogram_webhook-2.0.0/src/aiogram_webhook/engines/simple.py +101 -0
- aiogram_webhook-2.0.0/src/aiogram_webhook/engines/token.py +126 -0
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/routing/base.py +3 -3
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/routing/path.py +2 -2
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/routing/query.py +1 -1
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/security/__init__.py +2 -2
- aiogram_webhook-2.0.0/src/aiogram_webhook/security/checks/__init__.py +0 -0
- aiogram_webhook-2.0.0/src/aiogram_webhook/security/checks/check.py +17 -0
- aiogram_webhook-2.0.0/src/aiogram_webhook/security/checks/ip.py +83 -0
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/security/secret_token.py +17 -5
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/security/security.py +14 -8
- aiogram_webhook-1.0.0/.github/dependabot.yml +0 -11
- aiogram_webhook-1.0.0/.github/workflows/release.yml +0 -54
- aiogram_webhook-1.0.0/.github/workflows/tests.yml +0 -39
- aiogram_webhook-1.0.0/.gitignore +0 -207
- aiogram_webhook-1.0.0/CHANGELOG.md +0 -145
- aiogram_webhook-1.0.0/CONTRIBUTING.md +0 -78
- aiogram_webhook-1.0.0/LICENSE +0 -21
- aiogram_webhook-1.0.0/aiogram_webhook/__init__.py +0 -20
- aiogram_webhook-1.0.0/aiogram_webhook/adapters/base.py +0 -75
- aiogram_webhook-1.0.0/aiogram_webhook/adapters/fastapi.py +0 -43
- aiogram_webhook-1.0.0/aiogram_webhook/engines/simple.py +0 -91
- aiogram_webhook-1.0.0/aiogram_webhook/engines/token.py +0 -118
- aiogram_webhook-1.0.0/aiogram_webhook/security/checks/check.py +0 -14
- aiogram_webhook-1.0.0/aiogram_webhook/security/checks/ip.py +0 -89
- aiogram_webhook-1.0.0/tests/conftest.py +0 -14
- aiogram_webhook-1.0.0/tests/fixtures/__init__.py +0 -4
- aiogram_webhook-1.0.0/tests/fixtures/fixtures_bound_request.py +0 -39
- aiogram_webhook-1.0.0/tests/fixtures/fixtures_checks.py +0 -22
- aiogram_webhook-1.0.0/tests/test_ip_check.py +0 -202
- aiogram_webhook-1.0.0/tests/test_routing.py +0 -157
- aiogram_webhook-1.0.0/tests/test_secret_token.py +0 -49
- aiogram_webhook-1.0.0/tests/test_security.py +0 -77
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/adapters/__init__.py +0 -0
- {aiogram_webhook-1.0.0/aiogram_webhook/security/checks → aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/aiohttp}/__init__.py +0 -0
- {aiogram_webhook-1.0.0/tests → aiogram_webhook-2.0.0/src/aiogram_webhook/adapters/fastapi}/__init__.py +0 -0
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/engines/__init__.py +0 -0
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/routing/__init__.py +0 -0
- {aiogram_webhook-1.0.0 → aiogram_webhook-2.0.0/src}/aiogram_webhook/routing/static.py +0 -0
|
@@ -1,35 +1,36 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: aiogram-webhook
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: A python library for integrating webhook support with multiple web frameworks in aiogram. Organizes bot operation via webhooks for both single and multi-bot setups.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Project-URL: Issues, https://github.com/m-xim/aiogram-webhook/issues
|
|
8
|
-
Project-URL: Documentation, https://github.com/m-xim/aiogram-webhook#readme
|
|
5
|
+
Keywords: aiogram,telegram,webhook,fastapi,aiohttp,multibot
|
|
6
|
+
Author: m-xim
|
|
9
7
|
Author-email: m-xim <i@m-xim.ru>
|
|
10
8
|
License: MIT
|
|
11
|
-
License-File: LICENSE
|
|
12
|
-
Keywords: aiogram,aiohttp,fastapi,multibot,telegram,webhook
|
|
13
|
-
Classifier: Operating System :: OS Independent
|
|
14
9
|
Classifier: Programming Language :: Python :: 3
|
|
15
10
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
13
|
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
15
|
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
-
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
21
17
|
Requires-Dist: aiogram>=3.14.0
|
|
22
18
|
Requires-Dist: yarl>=1.17.0
|
|
19
|
+
Requires-Dist: aiohttp>=3.9.0 ; extra == 'aiohttp'
|
|
20
|
+
Requires-Dist: ruff ; extra == 'dev'
|
|
21
|
+
Requires-Dist: ty ; extra == 'dev'
|
|
22
|
+
Requires-Dist: pytest ; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest-asyncio ; extra == 'dev'
|
|
24
|
+
Requires-Dist: httpx ; extra == 'dev'
|
|
25
|
+
Requires-Dist: fastapi>=0.128.0 ; extra == 'fastapi'
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Project-URL: Homepage, https://github.com/m-xim/aiogram-webhook
|
|
28
|
+
Project-URL: Repository, https://github.com/m-xim/aiogram-webhook
|
|
29
|
+
Project-URL: Issues, https://github.com/m-xim/aiogram-webhook/issues
|
|
30
|
+
Project-URL: Documentation, https://github.com/m-xim/aiogram-webhook#readme
|
|
23
31
|
Provides-Extra: aiohttp
|
|
24
|
-
Requires-Dist: aiohttp>=3.9.0; extra == 'aiohttp'
|
|
25
32
|
Provides-Extra: dev
|
|
26
|
-
Requires-Dist: httpx; extra == 'dev'
|
|
27
|
-
Requires-Dist: pytest; extra == 'dev'
|
|
28
|
-
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
29
|
-
Requires-Dist: ruff; extra == 'dev'
|
|
30
|
-
Requires-Dist: ty; extra == 'dev'
|
|
31
33
|
Provides-Extra: fastapi
|
|
32
|
-
Requires-Dist: fastapi>=0.128.0; extra == 'fastapi'
|
|
33
34
|
Description-Content-Type: text/markdown
|
|
34
35
|
|
|
35
36
|
# aiogram-webhook
|
|
@@ -74,38 +75,43 @@ from fastapi import FastAPI
|
|
|
74
75
|
from aiogram import Bot, Dispatcher, Router
|
|
75
76
|
from aiogram.filters import CommandStart
|
|
76
77
|
from aiogram.types import Message
|
|
77
|
-
from aiogram_webhook import SimpleEngine, FastApiWebAdapter
|
|
78
|
+
from aiogram_webhook import SimpleEngine, FastApiWebAdapter, WebhookConfig
|
|
78
79
|
from aiogram_webhook.routing import StaticRouting
|
|
79
80
|
|
|
80
81
|
router = Router()
|
|
81
82
|
|
|
83
|
+
|
|
82
84
|
@router.message(CommandStart())
|
|
83
85
|
async def start(message: Message):
|
|
84
86
|
await message.answer("OK")
|
|
85
87
|
|
|
88
|
+
|
|
86
89
|
dispatcher = Dispatcher()
|
|
87
90
|
dispatcher.include_router(router)
|
|
88
91
|
bot = Bot("BOT_TOKEN")
|
|
89
92
|
|
|
90
|
-
|
|
93
|
+
|
|
94
|
+
engine = SimpleEngine(
|
|
91
95
|
dispatcher,
|
|
92
96
|
bot,
|
|
93
97
|
web_adapter=FastApiWebAdapter(),
|
|
94
98
|
routing=StaticRouting(url="https://example.com/webhook"),
|
|
99
|
+
webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"], drop_pending_updates=True),
|
|
95
100
|
# security=Security(...)
|
|
96
101
|
)
|
|
97
102
|
|
|
103
|
+
|
|
98
104
|
@asynccontextmanager
|
|
99
105
|
async def lifespan(app: FastAPI):
|
|
100
106
|
engine.register(app)
|
|
101
|
-
await engine.set_webhook(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
)
|
|
107
|
+
await engine.set_webhook() # Uses webhook_config defaults
|
|
108
|
+
# Or override specific params:
|
|
109
|
+
# await engine.set_webhook(max_connections=100)
|
|
105
110
|
await engine.on_startup(app)
|
|
106
111
|
yield
|
|
107
112
|
await engine.on_shutdown(app)
|
|
108
113
|
|
|
114
|
+
|
|
109
115
|
app = FastAPI(lifespan=lifespan)
|
|
110
116
|
```
|
|
111
117
|
|
|
@@ -114,29 +120,33 @@ app = FastAPI(lifespan=lifespan)
|
|
|
114
120
|
from aiogram import Bot, Dispatcher, Router
|
|
115
121
|
from aiogram.filters import CommandStart
|
|
116
122
|
from aiogram.types import Message
|
|
117
|
-
from aiogram_webhook import SimpleEngine, AiohttpWebAdapter
|
|
123
|
+
from aiogram_webhook import SimpleEngine, AiohttpWebAdapter, WebhookConfig
|
|
118
124
|
from aiogram_webhook.routing import StaticRouting
|
|
119
125
|
from aiohttp import web
|
|
120
126
|
|
|
121
127
|
router = Router()
|
|
122
128
|
|
|
129
|
+
|
|
123
130
|
@router.message(CommandStart())
|
|
124
131
|
async def start(message: Message):
|
|
125
132
|
await message.answer("OK")
|
|
126
133
|
|
|
127
|
-
|
|
134
|
+
|
|
135
|
+
async def on_startup(bot: Bot, webhook_engine: SimpleEngine) -> None:
|
|
128
136
|
await webhook_engine.set_webhook()
|
|
129
137
|
|
|
138
|
+
|
|
130
139
|
dispatcher = Dispatcher()
|
|
131
140
|
dispatcher.include_router(router)
|
|
132
141
|
dispatcher.startup.register(on_startup)
|
|
133
142
|
bot = Bot("BOT_TOKEN")
|
|
134
143
|
|
|
135
|
-
engine = SimpleEngine(
|
|
144
|
+
engine = SimpleEngine(
|
|
136
145
|
dispatcher,
|
|
137
146
|
bot,
|
|
138
147
|
web_adapter=AiohttpWebAdapter(),
|
|
139
148
|
routing=StaticRouting(url="https://example.com/webhook"),
|
|
149
|
+
webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"]),
|
|
140
150
|
# security=Security(...)
|
|
141
151
|
)
|
|
142
152
|
app = web.Application()
|
|
@@ -155,21 +165,23 @@ Used for serving a single Telegram bot. Suitable for most standard scenarios whe
|
|
|
155
165
|
|
|
156
166
|
- Connects aiogram `Dispatcher` and `Bot` to the selected web framework (FastAPI, aiohttp, etc.)
|
|
157
167
|
- Handles webhook requests for a single bot
|
|
158
|
-
- Requires explicit dispatcher, bot, web_adapter, and routing (security
|
|
168
|
+
- Requires explicit dispatcher, bot, web_adapter, and routing (security and webhook_config are optional)
|
|
159
169
|
|
|
160
170
|
**Example:**
|
|
161
171
|
```python
|
|
162
172
|
from aiogram import Bot, Dispatcher
|
|
163
|
-
from aiogram_webhook import SimpleEngine, FastApiWebAdapter
|
|
173
|
+
from aiogram_webhook import SimpleEngine, FastApiWebAdapter, WebhookConfig
|
|
164
174
|
from aiogram_webhook.routing import StaticRouting
|
|
165
175
|
|
|
166
176
|
bot = Bot("BOT_TOKEN")
|
|
167
177
|
dispatcher = Dispatcher()
|
|
178
|
+
|
|
168
179
|
engine = SimpleEngine(
|
|
169
180
|
dispatcher,
|
|
170
181
|
bot,
|
|
171
182
|
web_adapter=FastApiWebAdapter(),
|
|
172
183
|
routing=StaticRouting(url="https://example.com/webhook"),
|
|
184
|
+
webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"], drop_pending_updates=True),
|
|
173
185
|
# security=Security(...)
|
|
174
186
|
)
|
|
175
187
|
```
|
|
@@ -180,7 +192,7 @@ Allows you to serve multiple Telegram bots in a single application. Useful if yo
|
|
|
180
192
|
|
|
181
193
|
- Allows serving multiple bots via a single endpoint
|
|
182
194
|
- Uses the bot token for request routing
|
|
183
|
-
- Requires dispatcher, web_adapter, routing, bot_settings (
|
|
195
|
+
- Requires dispatcher, web_adapter, routing, bot_settings (optional), webhook_config (optional), and security (optional)
|
|
184
196
|
|
|
185
197
|
**Example:**
|
|
186
198
|
|
|
@@ -189,11 +201,12 @@ from aiogram import Dispatcher, Router
|
|
|
189
201
|
from aiogram.client.default import DefaultBotProperties
|
|
190
202
|
from aiogram.types import Message
|
|
191
203
|
from aiogram.filters import Command, CommandObject
|
|
192
|
-
from aiogram_webhook import TokenEngine, FastApiWebAdapter
|
|
204
|
+
from aiogram_webhook import TokenEngine, FastApiWebAdapter, WebhookConfig, BotConfig
|
|
193
205
|
from aiogram_webhook.routing import PathRouting
|
|
194
206
|
|
|
195
207
|
router = Router()
|
|
196
208
|
|
|
209
|
+
|
|
197
210
|
@router.message(Command("addbot"))
|
|
198
211
|
async def add_bot_handler(message: Message, command: CommandObject, webhook_engine: TokenEngine):
|
|
199
212
|
token = command.args
|
|
@@ -203,14 +216,17 @@ async def add_bot_handler(message: Message, command: CommandObject, webhook_engi
|
|
|
203
216
|
new_bot = await webhook_engine.set_webhook(token)
|
|
204
217
|
await message.answer(f"Bot #{new_bot.id} started!")
|
|
205
218
|
|
|
219
|
+
|
|
206
220
|
dispatcher = Dispatcher()
|
|
207
221
|
dispatcher.include_router(router)
|
|
208
222
|
|
|
223
|
+
|
|
209
224
|
engine = TokenEngine(
|
|
210
225
|
dispatcher,
|
|
211
226
|
web_adapter=FastApiWebAdapter(),
|
|
212
227
|
routing=PathRouting(url="https://example.com/webhook/{bot_token}"),
|
|
213
|
-
|
|
228
|
+
bot_config=BotConfig(default=DefaultBotProperties(parse_mode="HTML")),
|
|
229
|
+
webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"]),
|
|
214
230
|
# security=Security(...)
|
|
215
231
|
)
|
|
216
232
|
```
|
|
@@ -302,6 +318,12 @@ See [routing examples](/src/aiogram_webhook/routing) for implementation details.
|
|
|
302
318
|
|
|
303
319
|
---
|
|
304
320
|
|
|
321
|
+
## ⚙️ Webhook Configuration
|
|
322
|
+
|
|
323
|
+
`WebhookConfig` allows you to set default parameters for the Telegram [`setWebhook`](https://core.telegram.org/bots/api#setwebhook) API call. All parameters are optional and can be overridden when calling `engine.set_webhook()`.
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
305
327
|
## 🛡️ Security
|
|
306
328
|
|
|
307
329
|
aiogram-webhook provides a flexible and extensible security system for processing webhook requests. You can use built-in mechanisms, combine them, or implement your own checks.
|
|
@@ -310,8 +332,8 @@ aiogram-webhook provides a flexible and extensible security system for processin
|
|
|
310
332
|
from aiogram_webhook.security import Security, StaticSecretToken, IPCheck
|
|
311
333
|
|
|
312
334
|
security = Security(
|
|
313
|
-
IPCheck(),
|
|
314
|
-
secret_token=StaticSecretToken("YOUR_SECRET_TOKEN")
|
|
335
|
+
IPCheck(), # and other checks...
|
|
336
|
+
secret_token=StaticSecretToken("YOUR_SECRET_TOKEN"),
|
|
315
337
|
)
|
|
316
338
|
```
|
|
317
339
|
|
|
@@ -40,38 +40,43 @@ from fastapi import FastAPI
|
|
|
40
40
|
from aiogram import Bot, Dispatcher, Router
|
|
41
41
|
from aiogram.filters import CommandStart
|
|
42
42
|
from aiogram.types import Message
|
|
43
|
-
from aiogram_webhook import SimpleEngine, FastApiWebAdapter
|
|
43
|
+
from aiogram_webhook import SimpleEngine, FastApiWebAdapter, WebhookConfig
|
|
44
44
|
from aiogram_webhook.routing import StaticRouting
|
|
45
45
|
|
|
46
46
|
router = Router()
|
|
47
47
|
|
|
48
|
+
|
|
48
49
|
@router.message(CommandStart())
|
|
49
50
|
async def start(message: Message):
|
|
50
51
|
await message.answer("OK")
|
|
51
52
|
|
|
53
|
+
|
|
52
54
|
dispatcher = Dispatcher()
|
|
53
55
|
dispatcher.include_router(router)
|
|
54
56
|
bot = Bot("BOT_TOKEN")
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
|
|
59
|
+
engine = SimpleEngine(
|
|
57
60
|
dispatcher,
|
|
58
61
|
bot,
|
|
59
62
|
web_adapter=FastApiWebAdapter(),
|
|
60
63
|
routing=StaticRouting(url="https://example.com/webhook"),
|
|
64
|
+
webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"], drop_pending_updates=True),
|
|
61
65
|
# security=Security(...)
|
|
62
66
|
)
|
|
63
67
|
|
|
68
|
+
|
|
64
69
|
@asynccontextmanager
|
|
65
70
|
async def lifespan(app: FastAPI):
|
|
66
71
|
engine.register(app)
|
|
67
|
-
await engine.set_webhook(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
)
|
|
72
|
+
await engine.set_webhook() # Uses webhook_config defaults
|
|
73
|
+
# Or override specific params:
|
|
74
|
+
# await engine.set_webhook(max_connections=100)
|
|
71
75
|
await engine.on_startup(app)
|
|
72
76
|
yield
|
|
73
77
|
await engine.on_shutdown(app)
|
|
74
78
|
|
|
79
|
+
|
|
75
80
|
app = FastAPI(lifespan=lifespan)
|
|
76
81
|
```
|
|
77
82
|
|
|
@@ -80,29 +85,33 @@ app = FastAPI(lifespan=lifespan)
|
|
|
80
85
|
from aiogram import Bot, Dispatcher, Router
|
|
81
86
|
from aiogram.filters import CommandStart
|
|
82
87
|
from aiogram.types import Message
|
|
83
|
-
from aiogram_webhook import SimpleEngine, AiohttpWebAdapter
|
|
88
|
+
from aiogram_webhook import SimpleEngine, AiohttpWebAdapter, WebhookConfig
|
|
84
89
|
from aiogram_webhook.routing import StaticRouting
|
|
85
90
|
from aiohttp import web
|
|
86
91
|
|
|
87
92
|
router = Router()
|
|
88
93
|
|
|
94
|
+
|
|
89
95
|
@router.message(CommandStart())
|
|
90
96
|
async def start(message: Message):
|
|
91
97
|
await message.answer("OK")
|
|
92
98
|
|
|
93
|
-
|
|
99
|
+
|
|
100
|
+
async def on_startup(bot: Bot, webhook_engine: SimpleEngine) -> None:
|
|
94
101
|
await webhook_engine.set_webhook()
|
|
95
102
|
|
|
103
|
+
|
|
96
104
|
dispatcher = Dispatcher()
|
|
97
105
|
dispatcher.include_router(router)
|
|
98
106
|
dispatcher.startup.register(on_startup)
|
|
99
107
|
bot = Bot("BOT_TOKEN")
|
|
100
108
|
|
|
101
|
-
engine = SimpleEngine(
|
|
109
|
+
engine = SimpleEngine(
|
|
102
110
|
dispatcher,
|
|
103
111
|
bot,
|
|
104
112
|
web_adapter=AiohttpWebAdapter(),
|
|
105
113
|
routing=StaticRouting(url="https://example.com/webhook"),
|
|
114
|
+
webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"]),
|
|
106
115
|
# security=Security(...)
|
|
107
116
|
)
|
|
108
117
|
app = web.Application()
|
|
@@ -121,21 +130,23 @@ Used for serving a single Telegram bot. Suitable for most standard scenarios whe
|
|
|
121
130
|
|
|
122
131
|
- Connects aiogram `Dispatcher` and `Bot` to the selected web framework (FastAPI, aiohttp, etc.)
|
|
123
132
|
- Handles webhook requests for a single bot
|
|
124
|
-
- Requires explicit dispatcher, bot, web_adapter, and routing (security
|
|
133
|
+
- Requires explicit dispatcher, bot, web_adapter, and routing (security and webhook_config are optional)
|
|
125
134
|
|
|
126
135
|
**Example:**
|
|
127
136
|
```python
|
|
128
137
|
from aiogram import Bot, Dispatcher
|
|
129
|
-
from aiogram_webhook import SimpleEngine, FastApiWebAdapter
|
|
138
|
+
from aiogram_webhook import SimpleEngine, FastApiWebAdapter, WebhookConfig
|
|
130
139
|
from aiogram_webhook.routing import StaticRouting
|
|
131
140
|
|
|
132
141
|
bot = Bot("BOT_TOKEN")
|
|
133
142
|
dispatcher = Dispatcher()
|
|
143
|
+
|
|
134
144
|
engine = SimpleEngine(
|
|
135
145
|
dispatcher,
|
|
136
146
|
bot,
|
|
137
147
|
web_adapter=FastApiWebAdapter(),
|
|
138
148
|
routing=StaticRouting(url="https://example.com/webhook"),
|
|
149
|
+
webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"], drop_pending_updates=True),
|
|
139
150
|
# security=Security(...)
|
|
140
151
|
)
|
|
141
152
|
```
|
|
@@ -146,7 +157,7 @@ Allows you to serve multiple Telegram bots in a single application. Useful if yo
|
|
|
146
157
|
|
|
147
158
|
- Allows serving multiple bots via a single endpoint
|
|
148
159
|
- Uses the bot token for request routing
|
|
149
|
-
- Requires dispatcher, web_adapter, routing, bot_settings (
|
|
160
|
+
- Requires dispatcher, web_adapter, routing, bot_settings (optional), webhook_config (optional), and security (optional)
|
|
150
161
|
|
|
151
162
|
**Example:**
|
|
152
163
|
|
|
@@ -155,11 +166,12 @@ from aiogram import Dispatcher, Router
|
|
|
155
166
|
from aiogram.client.default import DefaultBotProperties
|
|
156
167
|
from aiogram.types import Message
|
|
157
168
|
from aiogram.filters import Command, CommandObject
|
|
158
|
-
from aiogram_webhook import TokenEngine, FastApiWebAdapter
|
|
169
|
+
from aiogram_webhook import TokenEngine, FastApiWebAdapter, WebhookConfig, BotConfig
|
|
159
170
|
from aiogram_webhook.routing import PathRouting
|
|
160
171
|
|
|
161
172
|
router = Router()
|
|
162
173
|
|
|
174
|
+
|
|
163
175
|
@router.message(Command("addbot"))
|
|
164
176
|
async def add_bot_handler(message: Message, command: CommandObject, webhook_engine: TokenEngine):
|
|
165
177
|
token = command.args
|
|
@@ -169,14 +181,17 @@ async def add_bot_handler(message: Message, command: CommandObject, webhook_engi
|
|
|
169
181
|
new_bot = await webhook_engine.set_webhook(token)
|
|
170
182
|
await message.answer(f"Bot #{new_bot.id} started!")
|
|
171
183
|
|
|
184
|
+
|
|
172
185
|
dispatcher = Dispatcher()
|
|
173
186
|
dispatcher.include_router(router)
|
|
174
187
|
|
|
188
|
+
|
|
175
189
|
engine = TokenEngine(
|
|
176
190
|
dispatcher,
|
|
177
191
|
web_adapter=FastApiWebAdapter(),
|
|
178
192
|
routing=PathRouting(url="https://example.com/webhook/{bot_token}"),
|
|
179
|
-
|
|
193
|
+
bot_config=BotConfig(default=DefaultBotProperties(parse_mode="HTML")),
|
|
194
|
+
webhook_config=WebhookConfig(allowed_updates=["message", "callback_query"]),
|
|
180
195
|
# security=Security(...)
|
|
181
196
|
)
|
|
182
197
|
```
|
|
@@ -268,6 +283,12 @@ See [routing examples](/src/aiogram_webhook/routing) for implementation details.
|
|
|
268
283
|
|
|
269
284
|
---
|
|
270
285
|
|
|
286
|
+
## ⚙️ Webhook Configuration
|
|
287
|
+
|
|
288
|
+
`WebhookConfig` allows you to set default parameters for the Telegram [`setWebhook`](https://core.telegram.org/bots/api#setwebhook) API call. All parameters are optional and can be overridden when calling `engine.set_webhook()`.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
271
292
|
## 🛡️ Security
|
|
272
293
|
|
|
273
294
|
aiogram-webhook provides a flexible and extensible security system for processing webhook requests. You can use built-in mechanisms, combine them, or implement your own checks.
|
|
@@ -276,8 +297,8 @@ aiogram-webhook provides a flexible and extensible security system for processin
|
|
|
276
297
|
from aiogram_webhook.security import Security, StaticSecretToken, IPCheck
|
|
277
298
|
|
|
278
299
|
security = Security(
|
|
279
|
-
IPCheck(),
|
|
280
|
-
secret_token=StaticSecretToken("YOUR_SECRET_TOKEN")
|
|
300
|
+
IPCheck(), # and other checks...
|
|
301
|
+
secret_token=StaticSecretToken("YOUR_SECRET_TOKEN"),
|
|
281
302
|
)
|
|
282
303
|
```
|
|
283
304
|
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "aiogram-webhook"
|
|
3
|
-
version = "
|
|
3
|
+
version = "2.0.0"
|
|
4
4
|
description = "A python library for integrating webhook support with multiple web frameworks in aiogram. Organizes bot operation via webhooks for both single and multi-bot setups."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
7
|
-
authors = [
|
|
8
|
-
{ name = "m-xim", email = "i@m-xim.ru" },
|
|
9
|
-
]
|
|
7
|
+
authors = [{ name = "m-xim", email = "i@m-xim.ru" }]
|
|
10
8
|
requires-python = ">=3.10"
|
|
11
|
-
packages = [{ include = "aiogram_webhook" }]
|
|
12
9
|
dependencies = [
|
|
13
10
|
"aiogram>=3.14.0",
|
|
14
11
|
"yarl>=1.17.0",
|
|
@@ -28,6 +25,7 @@ classifiers = [
|
|
|
28
25
|
"Programming Language :: Python :: 3.11",
|
|
29
26
|
"Programming Language :: Python :: 3.12",
|
|
30
27
|
"Programming Language :: Python :: 3.13",
|
|
28
|
+
"Programming Language :: Python :: 3.14",
|
|
31
29
|
"Topic :: Software Development :: Libraries",
|
|
32
30
|
"Operating System :: OS Independent",
|
|
33
31
|
]
|
|
@@ -54,11 +52,12 @@ dev = [
|
|
|
54
52
|
]
|
|
55
53
|
|
|
56
54
|
[build-system]
|
|
57
|
-
requires = ["
|
|
58
|
-
build-backend = "
|
|
55
|
+
requires = ["uv_build"]
|
|
56
|
+
build-backend = "uv_build"
|
|
57
|
+
|
|
58
|
+
[tool.uv]
|
|
59
|
+
package = true
|
|
59
60
|
|
|
60
|
-
[tool.hatch.build]
|
|
61
|
-
sources = ["src"]
|
|
62
61
|
|
|
63
62
|
[tool.semantic_release]
|
|
64
63
|
version_source = "pyproject"
|
|
@@ -70,59 +69,6 @@ version_toml = [
|
|
|
70
69
|
[tool.semantic_release.branches.main]
|
|
71
70
|
match = "main"
|
|
72
71
|
|
|
73
|
-
[tool.semantic_release.branches.
|
|
74
|
-
match = "
|
|
72
|
+
[tool.semantic_release.branches.develop]
|
|
73
|
+
match = "develop"
|
|
75
74
|
prerelease = true
|
|
76
|
-
|
|
77
|
-
[tool.ruff]
|
|
78
|
-
line-length = 120
|
|
79
|
-
exclude = [".venv", "__pycache__"]
|
|
80
|
-
|
|
81
|
-
[tool.ruff.format]
|
|
82
|
-
skip-magic-trailing-comma = false
|
|
83
|
-
|
|
84
|
-
[tool.ruff.lint]
|
|
85
|
-
select = ["ALL"]
|
|
86
|
-
ignore = [
|
|
87
|
-
"D",
|
|
88
|
-
"ANN",
|
|
89
|
-
"PLR09",
|
|
90
|
-
"COM812",
|
|
91
|
-
|
|
92
|
-
"ERA001",
|
|
93
|
-
"T201",
|
|
94
|
-
"RUF059",
|
|
95
|
-
"BLE001",
|
|
96
|
-
"RUF001",
|
|
97
|
-
"RUF003",
|
|
98
|
-
|
|
99
|
-
"TRY003",
|
|
100
|
-
"EM101",
|
|
101
|
-
|
|
102
|
-
"RUF002",
|
|
103
|
-
"EM102",
|
|
104
|
-
|
|
105
|
-
"FBT001",
|
|
106
|
-
"FBT002",
|
|
107
|
-
"TD002",
|
|
108
|
-
"FIX002",
|
|
109
|
-
|
|
110
|
-
"TD003",
|
|
111
|
-
"PLR2004",
|
|
112
|
-
"N806",
|
|
113
|
-
"E501",
|
|
114
|
-
"N815"
|
|
115
|
-
]
|
|
116
|
-
|
|
117
|
-
[tool.ruff.lint.flake8-tidy-imports]
|
|
118
|
-
ban-relative-imports = "all"
|
|
119
|
-
|
|
120
|
-
[tool.ruff.lint.per-file-ignores]
|
|
121
|
-
"tests/**/*" = [
|
|
122
|
-
"PLR2004",
|
|
123
|
-
"S101",
|
|
124
|
-
"TID252",
|
|
125
|
-
"S106",
|
|
126
|
-
"S105",
|
|
127
|
-
"ARG002"
|
|
128
|
-
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from aiogram_webhook.config.bot import BotConfig
|
|
2
|
+
from aiogram_webhook.config.webhook import WebhookConfig
|
|
3
|
+
from aiogram_webhook.engines.simple import SimpleEngine
|
|
4
|
+
from aiogram_webhook.engines.token import TokenEngine
|
|
5
|
+
|
|
6
|
+
__all__ = ["BotConfig", "SimpleEngine", "TokenEngine", "WebhookConfig"]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
from aiogram_webhook.adapters.aiohttp.adapter import AiohttpWebAdapter # noqa: F401
|
|
11
|
+
|
|
12
|
+
__all__.insert(0, "AiohttpWebAdapter")
|
|
13
|
+
except ImportError:
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
from aiogram_webhook.adapters.fastapi.adapter import FastApiWebAdapter # noqa: F401
|
|
18
|
+
|
|
19
|
+
__all__.insert(1, "FastApiWebAdapter")
|
|
20
|
+
except ImportError:
|
|
21
|
+
pass
|
|
@@ -1,44 +1,46 @@
|
|
|
1
|
-
from ipaddress import IPv4Address, IPv6Address
|
|
2
1
|
from typing import TYPE_CHECKING, Any, cast
|
|
3
2
|
|
|
4
3
|
from aiohttp.web import Application, Request
|
|
5
4
|
from aiohttp.web_response import Response, json_response
|
|
6
5
|
|
|
7
|
-
from aiogram_webhook.adapters.
|
|
6
|
+
from aiogram_webhook.adapters.aiohttp.mapping import AiohttpHeadersMapping, AiohttpQueryMapping
|
|
7
|
+
from aiogram_webhook.adapters.base_adapter import BoundRequest, WebAdapter
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
10
10
|
from asyncio import Transport
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class AiohttpBoundRequest(BoundRequest):
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
class AiohttpBoundRequest(BoundRequest[Request]):
|
|
14
|
+
def __init__(self, request: Request):
|
|
15
|
+
super().__init__(request)
|
|
16
|
+
self._headers = AiohttpHeadersMapping(self.request.headers)
|
|
17
|
+
self._query_params = AiohttpQueryMapping(self.request.query)
|
|
16
18
|
|
|
17
|
-
async def json(self)
|
|
19
|
+
async def json(self):
|
|
18
20
|
return await self.request.json()
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def query_param(self, name: str) -> Any | None:
|
|
24
|
-
return self.request.query.get(name)
|
|
25
|
-
|
|
26
|
-
def path_param(self, name: str) -> Any | None:
|
|
27
|
-
return self.request.match_info.get(name)
|
|
28
|
-
|
|
29
|
-
def ip(self) -> IPv4Address | IPv6Address | str | None:
|
|
22
|
+
@property
|
|
23
|
+
def client_ip(self):
|
|
30
24
|
if peer_name := cast("Transport", self.request.transport).get_extra_info("peername"):
|
|
31
25
|
return peer_name[0]
|
|
32
|
-
|
|
33
26
|
return None
|
|
34
27
|
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
@property
|
|
29
|
+
def headers(self) -> AiohttpHeadersMapping:
|
|
30
|
+
return self._headers
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def query_params(self) -> AiohttpQueryMapping:
|
|
34
|
+
return self._query_params
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def path_params(self):
|
|
38
|
+
return self.request.match_info
|
|
37
39
|
|
|
38
40
|
|
|
39
41
|
class AiohttpWebAdapter(WebAdapter):
|
|
40
42
|
def bind(self, request: Request) -> AiohttpBoundRequest:
|
|
41
|
-
return AiohttpBoundRequest(
|
|
43
|
+
return AiohttpBoundRequest(request=request)
|
|
42
44
|
|
|
43
45
|
def register(self, app: Application, path, handler, on_startup=None, on_shutdown=None) -> None:
|
|
44
46
|
async def endpoint(request: Request):
|
|
@@ -49,3 +51,6 @@ class AiohttpWebAdapter(WebAdapter):
|
|
|
49
51
|
app.on_startup.append(on_startup)
|
|
50
52
|
if on_shutdown is not None:
|
|
51
53
|
app.on_shutdown.append(on_shutdown)
|
|
54
|
+
|
|
55
|
+
def create_json_response(self, status: int, payload: dict[str, Any]) -> Response:
|
|
56
|
+
return json_response(status=status, data=payload)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from multidict import CIMultiDictProxy, MultiMapping
|
|
4
|
+
|
|
5
|
+
from aiogram_webhook.adapters.base_mapping import MappingABC
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AiohttpHeadersMapping(MappingABC[CIMultiDictProxy[str]]):
|
|
9
|
+
def getlist(self, name: str) -> list[Any]:
|
|
10
|
+
return self._mapping.getall(name, [])
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AiohttpQueryMapping(MappingABC[MultiMapping[str]]):
|
|
14
|
+
def getlist(self, name: str) -> list[Any]:
|
|
15
|
+
return self._mapping.getall(name, [])
|