Initial commit

This commit is contained in:
Forden 2020-04-06 00:12:41 +03:00
parent 0f5a395b72
commit af8294ff61
22 changed files with 214 additions and 0 deletions

39
bot.py Normal file
View 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
View File

29
data/config.py Normal file
View 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
View 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
View 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
View File

@ -0,0 +1 @@
from . import user

View 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
View 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
View File

View File

View File

View File

@ -0,0 +1 @@

View 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

View File

@ -0,0 +1 @@
from . import misc

View 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
View File

0
states/user/__init__.py Normal file
View File

0
utils/__init__.py Normal file
View File

0
utils/db_api/__init__.py Normal file
View File

55
utils/db_api/consts.py Normal file
View 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
View File

16
utils/redis/consts.py Normal file
View 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())