import 'dart:developer'; import 'dart:io'; import 'package:mnemo_cards_backend/api/mnemo_shelf.dart'; import 'package:mnemo_cards_backend/cron/add_free_packs.dart'; import 'package:mnemo_cards_backend/cron/backup.dart'; import 'package:mnemo_cards_backend/cron/cron_executor.dart'; import 'package:mnemo_cards_backend/cron/generate_promocodes.dart'; import 'package:mnemo_cards_backend/database/database.dart'; import 'package:mnemo_cards_backend/discounts/discounts_manager.dart'; import 'package:mnemo_cards_backend/user/user_manager.dart'; import 'package:mnemo_cards_backend/tests/test_manager.dart'; import 'api/di/injector.dart'; import 'cron/check_admins.dart'; import 'cron/check_payment.dart'; import 'cron/delete_old_archives.dart'; import 'cron/discount_campaign_task.dart'; import 'cron/tasks_seeder.dart'; import 'cron/test_generator.dart'; import 'cron/update_online_users.dart'; import 'packs/free_packs_distributor.dart'; late AppDatabase database; late final String WORK_DIR; /// Инициализация подключения к PostgreSQL Future _initDatabase() async { var attempt = 0; const maxAttempts = 5; while (attempt < maxAttempts) { print('Attempt ${attempt + 1}/$maxAttempts to connect to PostgreSQL...'); try { // Создать подключение из environment variables final db = AppDatabase.fromEnvironment(); // Проверить подключение await db.customSelect('SELECT 1').getSingle(); print('✅ Successfully connected to PostgreSQL'); return database = db; } catch (e, s) { print('❌ Error connecting to PostgreSQL: $e'); log('Error connecting to PostgreSQL: $e', error: e, stackTrace: s); attempt++; if (attempt < maxAttempts) { final delay = Duration(seconds: attempt * 5); print('Retrying in ${delay.inSeconds} seconds...'); await Future.delayed(delay); } } } throw Exception('Failed to connect to PostgreSQL after $maxAttempts attempts'); } void main() async { print('🚀 Starting Mnemo Cards Backend...'); // Читаем environment variables final backupDir = Platform.environment['BACKUP_DIR'] ?? '../backups/'; WORK_DIR = Platform.environment['WORK_DIR'] ?? '/root/mnemo_cards_backend'; final debugMode = Platform.environment['DEBUG'] == 'true' || Platform.environment['DEBUG'] == '1'; print('📂 Working directory: $WORK_DIR'); print('🐛 Debug mode: $debugMode'); print( 'running server in ${(await Process.run('pwd', [], runInShell: true)).stdout}', ); // For rustore payments // final rustoreEnabled = false; // if (rustoreEnabled) { // final pythonInit = await Process.run( // workingDirectory: WORK_DIR, // './prepare_python.sh', // [], // runInShell: true, // ); // print(pythonInit.stdout); // print(pythonInit.stderr); // } else { // log('\n\n*******\nRUSTORE IS DISABLED\n******\n\n', level: 1000); // } // Инициализация PostgreSQL try { await _initDatabase(); // Настройка зависимостей (AppDatabase уже регистрируется через @singleton в modules.dart) configureDependencies(); // Запуск API сервера print('🌐 Starting API server...'); await getIt().initV2(); // Запуск cron jobs print('⏰ Starting cron jobs...'); // ignore: unawaited_futures CronManager([ DeleteOldArchives(), CheckAdminsTask(database), getIt.get(), AddFreePacks(getIt.get(), database), Backup(backupDir), GeneratePromocodes(database), DiscountCampaignTask(getIt.get(), database), UpdateOnlineUsersTask(getIt.get()), TasksSeederTask(database), TestGeneratorTask(getIt.get(), database), ]).init(); print('✅ Backend started successfully!'); } catch (e, s) { print('❌ Fatal error starting backend: $e'); log('Fatal error starting backend: $e', error: e, stackTrace: s); exit(1); } // Обработка SIGTERM для graceful shutdown ProcessSignal.sigterm.watch().listen((signal) async { print('🛑 Received SIGTERM, shutting down gracefully...'); try { // Закрыть подключение к БД await database.close(); print('✅ Database connection closed'); } catch (e, s) { print('❌ Error closing database: $e'); log('Error closing database: $e', error: e, stackTrace: s); } exit(0); }); }