diff --git a/app/__main__.py b/app/__main__.py index b9b8549..68a440c 100644 --- a/app/__main__.py +++ b/app/__main__.py @@ -4,11 +4,11 @@ from asyncio import sleep from datetime import datetime import asyncio, sys -from aiogram import Bot import time from app.api import app -from app.bot import dp +from app.bot import dp as uploader_bot_dp +from app.client_bot import dp as client_bot_dp from app.core._config import SANIC_PORT, MYSQL_URI, TELEGRAM_API_KEY from app.core._utils.create_maria_tables import create_maria_tables from app.core.logger import make_log @@ -70,12 +70,15 @@ if __name__ == '__main__': if startup_target == '__main__': app.ctx.memory = Memory() app.ctx.memory._telegram_bot = Bot(TELEGRAM_API_KEY) - dp._s_memory = app.ctx.memory + + uploader_bot_dp._s_memory = app.ctx.memory + client_bot_dp._s_memory = app.ctx.memory app.ctx.memory._app = app app.add_task(execute_queue(app)) app.add_task(queue_daemon(app)) - app.add_task(dp.start_polling(app.ctx.memory._telegram_bot)) + app.add_task(uploader_bot_dp.start_polling(app.ctx.memory._telegram_bot)) + app.add_task(client_bot_dp.start_polling(app.ctx.memory._client_telegram_bot)) app.run(host='0.0.0.0', port=SANIC_PORT) else: diff --git a/app/bot/__init__.py b/app/bot/__init__.py index 886a75d..813684c 100644 --- a/app/bot/__init__.py +++ b/app/bot/__init__.py @@ -1,3 +1,5 @@ +# @MY_UploaderRobot + from datetime import datetime from aiogram import BaseMiddleware, Dispatcher diff --git a/app/client_bot/__init__.py b/app/client_bot/__init__.py new file mode 100644 index 0000000..7949f0c --- /dev/null +++ b/app/client_bot/__init__.py @@ -0,0 +1,80 @@ +# @MY_UploaderRobot + +from datetime import datetime + +from aiogram import BaseMiddleware, Dispatcher +from aiogram.fsm.storage.memory import MemoryStorage + +from app.client_bot.routers.index import main_router +from app.core.logger import logger +from app.core.models._telegram import Wrapped_CBotChat +from app.core.models.user import User +from app.core.storage import db_session + +dp = Dispatcher(storage=MemoryStorage()) + + +class UserDataMiddleware(BaseMiddleware): + async def __call__(self, handler, event, data): + update_body = event.message or event.callback_query + if not update_body: + return + + if update_body.from_user.is_bot is True: + return + + user_id = update_body.from_user.id + assert user_id >= 1 + # TODO: maybe make users cache + + with db_session(auto_commit=False) as session: + try: + user = session.query(User).filter_by(telegram_id=user_id).first() + except BaseException as e: + logger.error(f"Error when middleware getting user: {e}") + user = None + + if user is None: + logger.debug(f"User {user_id} not found. Creating new user") + user = User( + telegram_id=user_id, + username=update_body.from_user.username, + lang_code='en', + last_use=datetime.now(), + meta=dict(first_name=update_body.from_user.first_name or '', + last_name=update_body.from_user.last_name or '', username=update_body.from_user.username, + language_code=update_body.from_user.language_code, + is_premium=update_body.from_user.is_premium), + created=datetime.now() + ) + session.add(user) + session.commit() + else: + if user.username != update_body.from_user.username: + user.username = update_body.from_user.username + + updated_meta_fields = {} + if user.meta.get('first_name') != update_body.from_user.first_name: + updated_meta_fields['first_name'] = update_body.from_user.first_name + + if user.meta.get('last_name') != update_body.from_user.last_name: + updated_meta_fields['last_name'] = update_body.from_user.last_name + + user.meta = { + **user.meta, + **updated_meta_fields + } + + user.last_use = datetime.now() + session.commit() + + data['user'] = user + data['db_session'] = session + data['chat_wrap'] = Wrapped_CBotChat(data['bot'], chat_id=user_id) + data['memory'] = dp._s_memory + result = await handler(event, data) + return result + + +dp.update.outer_middleware(UserDataMiddleware()) +dp.include_router(main_router) diff --git a/app/client_bot/routers/home.py b/app/client_bot/routers/home.py new file mode 100644 index 0000000..5ef58df --- /dev/null +++ b/app/client_bot/routers/home.py @@ -0,0 +1,81 @@ +from app.core._utils.tg_process_template import tg_process_template +from app.core._keyboards import get_inline_keyboard +from app.core.logger import logger +from app.core.models.wallet_connection import WalletConnection +from app.core._blockchain.ton.connect import TonConnect, unpack_wallet_info +from app.core._config import WEB_APP_URLS +from aiogram import types, Router, F +from aiogram.filters import Command +from tonsdk.utils import Address + + +main_router = Router() + + +async def send_home_menu(chat_wrap, user, wallet_connection, **kwargs): + return await tg_process_template( + chat_wrap, user.translated('home_menu').format( + wallet_address=Address(wallet_connection.wallet_address).to_string(1, 1, 1), + name=user.front_format(plain_text=True), + ), keyboard=get_inline_keyboard([ + [{ + 'text': user.translated('ownedContent_button'), + 'callback_data': 'ownedContent' + }], + [{ + 'text': user.translated('disconnectWallet_button'), + 'callback_data': 'disconnectWallet' + }] + ]), **kwargs + ) + + +async def send_connect_wallets_list(db_session, chat_wrap, user, **kwargs): + ton_connect, ton_connection = TonConnect.by_user(db_session, user, callback_fn=()) + await ton_connect.restore_connection() + wallets = ton_connect._sdk_client.get_wallets() + message_text = user.translated("connectWalletsList_menu") + return await tg_process_template( + chat_wrap, message_text, + keyboard=get_inline_keyboard([ + [ + { + 'text': f"{wallets[i]['name']}", + 'callback_data': f"initTonconnect_{wallets[i]['app_name']}" + } if i < len(wallets) else None, + { + 'text': f"{wallets[i + 1]['name']}", + 'callback_data': f"initTonconnect_{wallets[i + 1]['app_name']}" + } if i + 1 < len(wallets) else None, + ] + for i in range(0, len(wallets), 2) + ]), **kwargs + ) + + +async def t_home_menu(__msg, **extra): + memory, user, db_session, chat_wrap = extra['memory'], extra['user'], extra['db_session'], extra['chat_wrap'] + if extra.get('state'): + await extra['state'].clear() + + if isinstance(__msg, types.CallbackQuery): + message_id = __msg.message.message_id + elif isinstance(__msg, types.Message): + message_id = __msg.message_id + else: + message_id = None + + wallet_connection = db_session.query(WalletConnection).filter( + WalletConnection.user_id == user.id, + WalletConnection.invalidated == False + ).first() + + if not wallet_connection: + return await send_connect_wallets_list(db_session, chat_wrap, user, message_id=message_id) + + return await send_home_menu(chat_wrap, user, wallet_connection, message_id=message_id) + + +main_router.message.register(t_home_menu, Command('start')) +main_router.callback_query.register(t_home_menu, F.data == 'home') +router = main_router diff --git a/app/client_bot/routers/index.py b/app/client_bot/routers/index.py new file mode 100644 index 0000000..85a9bc2 --- /dev/null +++ b/app/client_bot/routers/index.py @@ -0,0 +1,38 @@ +import os +import sys +import traceback + +from aiogram import types, Router, F +from aiogram.filters import Command + +from app.client_bot.routers.home import router as home_router +from app.core.logger import logger + +main_router = Router() +main_router.include_routers(home_router) + +closing_router = Router() + + +@closing_router.message() +async def t_index(message: types.Message, **extra): + return await message.answer(extra['user'].translated('error_unknownCommand'), parse_mode='html') + +main_router.include_routers(closing_router) + + +@main_router.error() +async def t_index_error(err_event: types.ErrorEvent, **extra): + try: + raise err_event.exception + except BaseException as e: + exc_type, exc_obj, exc_tb = sys.exc_info() + + try: + filename = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] + except: + filename = None + + logger.error(f"""Error: {e} +-/ {exc_type} {exc_obj} {filename} {exc_tb.tb_frame.f_lineno}""") + traceback.print_tb(exc_tb) diff --git a/app/core/_config.py b/app/core/_config.py index 058f3a1..967f65b 100644 --- a/app/core/_config.py +++ b/app/core/_config.py @@ -15,6 +15,8 @@ CONFIG_FILE = os.getenv('CONFIG_FILE') or f"{UPLOADS_DIR}/../config/config" TELEGRAM_API_KEY = os.environ.get('TELEGRAM_API_KEY') assert TELEGRAM_API_KEY, "Telegram API_KEY required" +CLIENT_TELEGRAM_API_KEY = os.environ.get('CLIENT_TELEGRAM_API_KEY') +assert CLIENT_TELEGRAM_API_KEY, "Client Telegram API_KEY required" MYSQL_URI = os.environ['MYSQL_URI'] MYSQL_DATABASE = os.environ['MYSQL_DATABASE'] @@ -28,7 +30,7 @@ _now_str = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") LOG_FILEPATH = f"{LOG_DIR}/{_now_str}.log" WEB_APP_URLS = { - 'uploadContent': f"https://web2-client.vercel.app/uploadContent" + 'uploadContent': f"https://music-ui.letsw.app/uploadContent" } ALLOWED_CONTENT_TYPES = [ diff --git a/app/core/background/indexator_service.py b/app/core/background/indexator_service.py index 9c07d6e..27f5488 100644 --- a/app/core/background/indexator_service.py +++ b/app/core/background/indexator_service.py @@ -12,10 +12,10 @@ async def main(): await send_status("indexator", f"working (seqno={seqno})") seqno += 1 -if __name__ == '__main__': - loop = asyncio.get_event_loop() - loop.run_until_complete(main()) - loop.close() +# if __name__ == '__main__': +# loop = asyncio.get_event_loop() +# loop.run_until_complete(main()) +# loop.close() diff --git a/app/core/background/ton_service.py b/app/core/background/ton_service.py index 6183593..d327d34 100644 --- a/app/core/background/ton_service.py +++ b/app/core/background/ton_service.py @@ -64,10 +64,10 @@ async def main(): await send_status("ton", f"working (seqno={sw_seqno_value})") -if __name__ == '__main__': - loop = asyncio.get_event_loop() - loop.run_until_complete(main()) - loop.close() +# if __name__ == '__main__': +# loop = asyncio.get_event_loop() +# loop.run_until_complete(main()) +# loop.close() diff --git a/app/core/background/uploader_service.py b/app/core/background/uploader_service.py index 515c197..4fff2b5 100644 --- a/app/core/background/uploader_service.py +++ b/app/core/background/uploader_service.py @@ -24,10 +24,10 @@ async def main(): make_log("Uploader", f"Error: {e}", level="error") await asyncio.sleep(3) -if __name__ == '__main__': - loop = asyncio.get_event_loop() - loop.run_until_complete(main()) - loop.close() +# if __name__ == '__main__': +# loop = asyncio.get_event_loop() +# loop.run_until_complete(main()) +# loop.close() diff --git a/app/core/models/memory.py b/app/core/models/memory.py index 647d6ed..6434130 100644 --- a/app/core/models/memory.py +++ b/app/core/models/memory.py @@ -2,7 +2,9 @@ import asyncio from contextlib import asynccontextmanager from datetime import datetime, timedelta +from aiogram import Bot from app.core.logger import make_log +from app.core._config import TELEGRAM_API_KEY, CLIENT_TELEGRAM_API_KEY from datetime import datetime @@ -32,6 +34,9 @@ class Memory: } } + self._telegram_bot = Bot(TELEGRAM_API_KEY) + self._client_telegram_bot = Bot(CLIENT_TELEGRAM_API_KEY) + @asynccontextmanager async def transaction(self, desc=""): make_log("Memory.transaction", f"Starting transaction; {desc}", level='debug')