Initial commit
This commit is contained in:
parent
0f5a395b72
commit
af8294ff61
39
bot.py
Normal file
39
bot.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
from aiogram import Bot, Dispatcher, types
|
||||||
|
from aiogram.contrib.fsm_storage.redis import RedisStorage2
|
||||||
|
from aiohttp import web
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
import filters
|
||||||
|
import handlers
|
||||||
|
from data import config
|
||||||
|
|
||||||
|
bot = Bot(token=config.BOT_TOKEN, parse_mode=types.ParseMode.HTML)
|
||||||
|
storage = RedisStorage2(**config.aiogram_redis)
|
||||||
|
dp = Dispatcher(bot, storage=storage)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
|
async def on_startup(web_app: web.Application):
|
||||||
|
filters.setup(dp)
|
||||||
|
handlers.user.setup(dp)
|
||||||
|
await dp.bot.delete_webhook()
|
||||||
|
await dp.bot.set_webhook(config.WEBHOOK_URL)
|
||||||
|
|
||||||
|
|
||||||
|
async def execute(req: web.Request) -> web.Response:
|
||||||
|
upds = [types.Update(**(await req.json()))]
|
||||||
|
Bot.set_current(dp.bot)
|
||||||
|
Dispatcher.set_current(dp)
|
||||||
|
try:
|
||||||
|
await dp.process_updates(upds)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
finally:
|
||||||
|
return web.Response()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app = web.Application()
|
||||||
|
app.on_startup.append(on_startup)
|
||||||
|
app.add_routes([web.post('/webhook/{token}', execute)])
|
||||||
|
web.run_app(app, port=5151, host='localhost')
|
0
data/__init__.py
Normal file
0
data/__init__.py
Normal file
29
data/config.py
Normal file
29
data/config.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
BOT_TOKEN = ''
|
||||||
|
WEBHOOK_URL = ''
|
||||||
|
|
||||||
|
admins = []
|
||||||
|
|
||||||
|
ip = {
|
||||||
|
'db': '',
|
||||||
|
'redis': '',
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_info = {
|
||||||
|
'host': ip['db'],
|
||||||
|
'user': '',
|
||||||
|
'password': '',
|
||||||
|
'db': '',
|
||||||
|
'maxsize': 5,
|
||||||
|
'port': 3306,
|
||||||
|
}
|
||||||
|
|
||||||
|
aiogram_redis = {
|
||||||
|
'host': ip['redis'],
|
||||||
|
'password': ''
|
||||||
|
}
|
||||||
|
|
||||||
|
redis = {
|
||||||
|
'address': (ip['redis'], 6379),
|
||||||
|
'password': '',
|
||||||
|
'encoding': 'utf8'
|
||||||
|
}
|
7
filters/__init__.py
Normal file
7
filters/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from aiogram import Dispatcher
|
||||||
|
|
||||||
|
from .is_admin import AdminFilter
|
||||||
|
|
||||||
|
|
||||||
|
def setup(dp: Dispatcher):
|
||||||
|
dp.filters_factory.bind(AdminFilter)
|
14
filters/is_admin.py
Normal file
14
filters/is_admin.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
from aiogram import types
|
||||||
|
from aiogram.dispatcher.filters import BoundFilter
|
||||||
|
|
||||||
|
from data import config
|
||||||
|
|
||||||
|
|
||||||
|
class AdminFilter(BoundFilter):
|
||||||
|
key = 'is_admin'
|
||||||
|
|
||||||
|
def __init__(self, is_admin):
|
||||||
|
self.is_admin = is_admin
|
||||||
|
|
||||||
|
async def check(self, message: types.Message):
|
||||||
|
return message.from_user.id in config.admins
|
1
handlers/__init__.py
Normal file
1
handlers/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
from . import user
|
8
handlers/user/__init__.py
Normal file
8
handlers/user/__init__.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
from aiogram import Dispatcher
|
||||||
|
from aiogram.dispatcher.filters import CommandStart
|
||||||
|
|
||||||
|
from .start import bot_start
|
||||||
|
|
||||||
|
|
||||||
|
def setup(dp: Dispatcher):
|
||||||
|
dp.register_message_handler(start, CommandStart())
|
5
handlers/user/start.py
Normal file
5
handlers/user/start.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from aiogram import types
|
||||||
|
|
||||||
|
|
||||||
|
async def bot_start(msg: types.Message):
|
||||||
|
await msg.answer(f'Привет, {msg.from_user.full_name}!')
|
0
keyboards/__init__.py
Normal file
0
keyboards/__init__.py
Normal file
0
keyboards/default/__init__.py
Normal file
0
keyboards/default/__init__.py
Normal file
0
keyboards/inline/__init__.py
Normal file
0
keyboards/inline/__init__.py
Normal file
1
keyboards/inline/callbacks.py
Normal file
1
keyboards/inline/callbacks.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
21
keyboards/inline/consts.py
Normal file
21
keyboards/inline/consts.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
from typing import List, Tuple, Dict
|
||||||
|
|
||||||
|
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
|
from aiogram.utils.callback_data import CallbackData
|
||||||
|
|
||||||
|
from . import utils
|
||||||
|
|
||||||
|
|
||||||
|
class InlineConstructor:
|
||||||
|
@staticmethod
|
||||||
|
def _create_kb(actions: List[Tuple[str, Dict[str, str], CallbackData]], schema: List[int]) -> InlineKeyboardMarkup:
|
||||||
|
btns = []
|
||||||
|
for a, b, c in actions:
|
||||||
|
btns.append(
|
||||||
|
InlineKeyboardButton(
|
||||||
|
text=a,
|
||||||
|
callback_data=c.new(**b)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
kb = utils.misc.arrange_inline_schema(btns, schema)
|
||||||
|
return kb
|
1
keyboards/inline/utils/__init__.py
Normal file
1
keyboards/inline/utils/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
from . import misc
|
17
keyboards/inline/utils/misc.py
Normal file
17
keyboards/inline/utils/misc.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
||||||
|
|
||||||
|
|
||||||
|
def arrange_inline_schema(buttons: List[InlineKeyboardButton], count: List[int]) -> InlineKeyboardMarkup:
|
||||||
|
kb = InlineKeyboardMarkup()
|
||||||
|
btns = buttons
|
||||||
|
kb.row_width = max(count)
|
||||||
|
if sum(count) != len(buttons):
|
||||||
|
raise ValueError('Количество кнопок не совпадает со схемой')
|
||||||
|
tmplist = [[InlineKeyboardButton('') for _ in range(count[i])] for i in range(len(count))]
|
||||||
|
for a in range(len(tmplist)):
|
||||||
|
for b in range(len(tmplist[a])):
|
||||||
|
tmplist[a][b] = btns.pop(0)
|
||||||
|
kb.inline_keyboard = tmplist
|
||||||
|
return kb
|
0
states/__init__.py
Normal file
0
states/__init__.py
Normal file
0
states/user/__init__.py
Normal file
0
states/user/__init__.py
Normal file
0
utils/__init__.py
Normal file
0
utils/__init__.py
Normal file
0
utils/db_api/__init__.py
Normal file
0
utils/db_api/__init__.py
Normal file
55
utils/db_api/consts.py
Normal file
55
utils/db_api/consts.py
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import asyncio
|
||||||
|
from typing import Optional, Dict, Any, Union, List
|
||||||
|
|
||||||
|
import aiomysql
|
||||||
|
|
||||||
|
from data import config
|
||||||
|
|
||||||
|
connection_pool = None
|
||||||
|
mainloop = asyncio.get_event_loop()
|
||||||
|
|
||||||
|
|
||||||
|
async def main(loop):
|
||||||
|
global connection_pool
|
||||||
|
connection_pool = await aiomysql.create_pool(**config.mysql_info, loop=loop)
|
||||||
|
|
||||||
|
|
||||||
|
class RawConnection:
|
||||||
|
@staticmethod
|
||||||
|
async def _make_request(
|
||||||
|
sql: str,
|
||||||
|
params: Union[tuple, List[tuple]] = None,
|
||||||
|
fetch: bool = False,
|
||||||
|
mult: bool = False,
|
||||||
|
retries_count: int = 5
|
||||||
|
) -> Optional[Union[List[Dict[str, Any]], Dict[str, Any]]]:
|
||||||
|
global connection_pool
|
||||||
|
async with connection_pool.acquire() as conn:
|
||||||
|
conn: aiomysql.Connection = conn
|
||||||
|
async with conn.cursor(aiomysql.DictCursor) as cur:
|
||||||
|
cur: aiomysql.DictCursor = cur
|
||||||
|
for i in range(retries_count):
|
||||||
|
try:
|
||||||
|
if isinstance(params, list):
|
||||||
|
await cur.executemany(sql, params)
|
||||||
|
else:
|
||||||
|
await cur.execute(sql, params)
|
||||||
|
except aiomysql.OperationalError as e:
|
||||||
|
if 'Deadlock found' in str(e):
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
except aiomysql.InternalError as e:
|
||||||
|
if 'Deadlock found' in str(e):
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
if fetch:
|
||||||
|
if mult:
|
||||||
|
r = await cur.fetchall()
|
||||||
|
else:
|
||||||
|
r = await cur.fetchone()
|
||||||
|
return r
|
||||||
|
else:
|
||||||
|
await conn.commit()
|
||||||
|
|
||||||
|
|
||||||
|
mainloop.run_until_complete(main(mainloop))
|
0
utils/redis/__init__.py
Normal file
0
utils/redis/__init__.py
Normal file
16
utils/redis/consts.py
Normal file
16
utils/redis/consts.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import asyncio
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import aioredis
|
||||||
|
|
||||||
|
from data import config
|
||||||
|
|
||||||
|
data_pool: Optional[aioredis.Redis] = None
|
||||||
|
|
||||||
|
|
||||||
|
async def create_pools():
|
||||||
|
global data_pool
|
||||||
|
data_pool = await aioredis.create_redis_pool(**config.redis, db=1)
|
||||||
|
|
||||||
|
|
||||||
|
asyncio.get_event_loop().run_until_complete(create_pools())
|
Loading…
Reference in New Issue
Block a user