Some refactoring and started second bot

This commit is contained in:
2023-11-27 22:04:50 +03:00
parent b14eeb8342
commit a848733422
8 changed files with 108 additions and 63 deletions

View File

@@ -1,3 +1,5 @@
TOKEN= TOKEN=
PROXY_TOKEN=
API_URL="http://localhost:3000" API_URL="http://localhost:3000"

View File

@@ -1,6 +1,6 @@
from typing import Any, List from typing import List
from aiogram import Bot, F, Router, types from aiogram import Bot, F, types
from aiogram.filters import Command from aiogram.filters import Command
from aiogram.fsm.context import FSMContext from aiogram.fsm.context import FSMContext
from aiogram.utils.media_group import MediaGroupBuilder from aiogram.utils.media_group import MediaGroupBuilder
@@ -9,6 +9,7 @@ import neuroapi.types as neuroTypes
from handlers.filters.new_post import (ChangePosts, NewPostFilter, from handlers.filters.new_post import (ChangePosts, NewPostFilter,
NewSoloPostFilter) NewSoloPostFilter)
from handlers.filters.reply_to_user import ReplyToUser from handlers.filters.reply_to_user import ReplyToUser
from handlers.handler import Handler
from handlers.middlewares.user import AdminMiddleware from handlers.middlewares.user import AdminMiddleware
from handlers.states.change_post import ChangePost from handlers.states.change_post import ChangePost
from neuroapi import neuroapi from neuroapi import neuroapi
@@ -23,13 +24,9 @@ def get_post_info(post: neuroTypes.Post, post_id: int) -> str:
return s return s
class Admin_commands: class AdminCommands(Handler):
bot: Bot
router: Router
def __init__(self, bot: Bot) -> None: def __init__(self, bot: Bot) -> None:
self.bot = bot super().__init__(bot)
self.router = Router()
self.router.message.middleware(AdminMiddleware()) self.router.message.middleware(AdminMiddleware())
@self.router.message(NewPostFilter()) @self.router.message(NewPostFilter())
@@ -210,9 +207,4 @@ class Admin_commands:
except Exception as e: except Exception as e:
print(e) print(e)
def __call__(self, *args: Any, **kwds: Any) -> Router:
return self.router
def setup(bot: Bot) -> Router:
return Admin_commands(bot)()

16
handlers/handler.py Normal file
View File

@@ -0,0 +1,16 @@
from typing import Any
from aiogram import Bot, Router
class Handler:
bot: Bot
router: Router
def __init__(self, bot: Bot) -> None:
assert isinstance(bot, Bot)
self.bot = bot
self.router = Router()
def __call__(self) -> Router:
return self.router

View File

@@ -1,19 +1,16 @@
from typing import Any, List from typing import List
from aiogram import Bot, F, Router, types from aiogram import Bot, F, types
from handlers.handler import Handler
from neuroapi import neuroapi from neuroapi import neuroapi
from neuroapi.types import Admin as AdminType from neuroapi.types import Admin as AdminType
class User_commands: class UserCommands(Handler):
bot: Bot
router: Router
def __init__(self, bot: Bot) -> None: def __init__(self, bot: Bot) -> None:
self.bot = bot super().__init__(bot)
self.router = Router()
@self.router.message(F.chat.type == 'private') @self.router.message(F.chat.type == 'private')
async def forward_post(message: types.Message): async def forward_post(message: types.Message):
@@ -27,9 +24,3 @@ class User_commands:
canReply = False canReply = False
await message.reply('Ваше сообщение было отправлено администраторам'+('' if canReply else '\nНо они не смогут вам ответить из-за ваших настроек конфиденциальности.')) await message.reply('Ваше сообщение было отправлено администраторам'+('' if canReply else '\nНо они не смогут вам ответить из-за ваших настроек конфиденциальности.'))
def __call__(self, *args: Any, **kwds: Any) -> Router:
return self.router
def setup(bot: Bot) -> Router:
return User_commands(bot)()

69
main.py
View File

@@ -1,37 +1,68 @@
import asyncio import asyncio
import logging import logging
import os import signal
import sys import sys
from os.path import dirname, join
# import aioschedule as schedule # import aioschedule as schedule
import dotenv from aiogram import Bot, Dispatcher
from aiogram import Bot, Dispatcher, types
from aiogram.filters import CommandStart
dotenv.load_dotenv() from handlers.admin_commands import AdminCommands
from handlers.handler import Handler
from handlers.user_commands import UserCommands
from neuroapi.config import Config
token = os.getenv('TOKEN')
bot = Bot(token) class NeuroApiBot:
dp = Dispatcher() bot: Bot
dp: Dispatcher
@dp.message(CommandStart()) _instances = {}
async def start_message(message: types.Message):
await message.answer('Добро пожаловать в бота ')
handlers_dir = join(dirname(__file__), 'handlers') def __init__(self, token: str) -> None:
self.bot = Bot(token)
self.dp = Dispatcher()
self._instances
for filename in os.listdir(handlers_dir): def __new__(cls, token: str) -> 'NeuroApiBot':
if filename.endswith('.py'): assert isinstance(token, str)
module_name = filename[:-3] if token not in cls._instances:
setup = __import__(f"handlers.{module_name}", locals(), globals(), ['setup']).setup cls._instances[token] = super(NeuroApiBot, cls).__new__(cls)
dp.include_router(setup(bot)) return cls._instances[token]
def include_router(self, *routerClasses: Handler) -> None:
for routerClass in routerClasses:
assert issubclass(routerClass, Handler)
self.dp.include_routers(routerClass(self.bot)())
async def start(self, skip_updates=True):
await self.dp.start_polling(self.bot, skip_updates=skip_updates)
async def delay_bot()->None:
if Config().token is None:
print('Delay bot needs token in environment')
return
bot = NeuroApiBot(Config().token)
bot.include_router(AdminCommands, UserCommands)
await bot.start()
async def proxy_bot()->None:
if Config().proxy_token is None:
print('Proxy bot needs token in environment')
return
bot = NeuroApiBot(Config().proxy_token)
bot.include_router()
await bot.start()
async def main() -> None: async def main() -> None:
await dp.start_polling(bot, skip_updates=True) tasks = [asyncio.create_task(delay_bot()), asyncio.create_task(proxy_bot())]
await asyncio.gather(*tasks)
if __name__ == '__main__': if __name__ == '__main__':
logging.basicConfig(level=logging.INFO, stream=sys.stdout) logging.basicConfig(level=logging.INFO, stream=sys.stdout)
loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'):
loop.add_signal_handler(getattr(signal, signame), loop.stop)
try:
asyncio.run(main()) asyncio.run(main())
except KeyboardInterrupt:
pass

View File

@@ -1,21 +1,15 @@
import os import os
import tomllib import tomllib
from typing import List, Self, TypeVar from typing import List, Optional
from attr import dataclass from attr import dataclass
from dotenv import load_dotenv from dotenv import load_dotenv
from neuroapi.types import Singleton
from .types._helpers import * from .types._helpers import *
class _Singleton:
_instances = {}
def __new__(cls) -> Self:
if cls not in cls._instances:
cls._instances[cls] = super(_Singleton, cls).__new__(cls)
return cls._instances[cls]
@dataclass @dataclass
class Settings: class Settings:
time: List[str] time: List[str]
@@ -31,9 +25,11 @@ class Settings:
result['time'] = from_list(from_str, self.time) result['time'] = from_list(from_str, self.time)
return result return result
class Config(_Singleton): class Config(Singleton):
api_url: str api_url: str
settings: Settings settings: Settings
token: Optional[str]
proxy_token: Optional[str]
def __init__(self): def __init__(self):
load_dotenv(os.path.join(os.path.dirname(__file__), '..', '.env')) load_dotenv(os.path.join(os.path.dirname(__file__), '..', '.env'))
if not os.path.exists(os.path.join(os.path.dirname(__file__), '..', 'settings.toml')): raise Exception('Settings.toml must be in root folder') if not os.path.exists(os.path.join(os.path.dirname(__file__), '..', 'settings.toml')): raise Exception('Settings.toml must be in root folder')
@@ -41,3 +37,9 @@ class Config(_Singleton):
settings = tomllib.load(f) settings = tomllib.load(f)
self.settings = Settings.from_dict(settings) self.settings = Settings.from_dict(settings)
self.api_url = os.environ.get('API_URL') self.api_url = os.environ.get('API_URL')
self.token = os.environ.get('TOKEN')
if self.token == '':
self.token = None
self.proxy_token = os.environ.get('PROXY_TOKEN')
if self.proxy_token == '':
self.proxy_token = None

View File

@@ -1,4 +1,5 @@
from ._post import Post
from ._image import Image
from ._admin import Admin from ._admin import Admin
from ._image import Image
from ._post import Post
from ._singleton import Singleton
from ._user import User from ._user import User

View File

@@ -0,0 +1,10 @@
from typing import Self
class Singleton:
_instances = {}
def __new__(cls, *args, **kwargs) -> Self:
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__new__(cls)
return cls._instances[cls]