Spaces:
Running
Running
| # PyFundaments: A Secure Python Architecture | |
| # Copyright 2008-2025 - Volkan Kücükbudak | |
| # Apache License V. 2 | |
| # Repo: https://github.com/VolkanSah/PyFundaments | |
| # main.py | |
| # This is the main entry point of the application. | |
| # It now handles asynchronous initialization of the fundament modules. | |
| import sys | |
| import logging | |
| import asyncio | |
| import os | |
| from typing import Dict, Any, Optional | |
| import importlib.util | |
| import datetime | |
| if 'fundaments' in sys.modules: | |
| del sys.modules['fundaments'] | |
| # We import our core modules from the "fundaments" directory. | |
| try: | |
| from fundaments.config_handler import config_service | |
| from fundaments.postgresql import init_db_pool, close_db_pool | |
| from fundaments.encryption import Encryption | |
| from fundaments.access_control import AccessControl | |
| from fundaments.user_handler import UserHandler | |
| from fundaments.security import Security | |
| from fundaments.debug import PyFundamentsDebug | |
| except ImportError as e: | |
| print(f"Error: Failed to import a fundament module: {e}") | |
| print("Please ensure the modules and dependencies are present.") | |
| sys.exit(1) | |
| # Debug run | |
| debug = PyFundamentsDebug() | |
| debug.run() | |
| # Logger configuration - conditional based on ENV | |
| log_level = os.getenv('LOG_LEVEL', 'INFO').upper() | |
| log_to_tmp = os.getenv('LOG_TO_TMP', 'false').lower() == 'true' | |
| enable_public_logs = os.getenv('ENABLE_PUBLIC_LOGS', 'true').lower() == 'true' | |
| if enable_public_logs: | |
| if log_to_tmp: | |
| log_file = '/tmp/pyfundaments.log' | |
| logging.basicConfig( | |
| level=getattr(logging, log_level), | |
| format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', | |
| handlers=[ | |
| logging.FileHandler(log_file), | |
| logging.StreamHandler() | |
| ] | |
| ) | |
| else: | |
| logging.basicConfig( | |
| level=getattr(logging, log_level), | |
| format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' | |
| ) | |
| else: | |
| # Silent mode - only critical errors | |
| logging.basicConfig(level=logging.CRITICAL) | |
| logger = logging.getLogger('main_app_loader') | |
| async def initialize_fundaments() -> Dict[str, Any]: | |
| """ | |
| Initializes core application services conditionally based on available ENV variables. | |
| Only loads services for which the required configuration is present. | |
| """ | |
| logger.info("Starting conditional initialization of fundament modules...") | |
| fundaments = { | |
| "config": config_service | |
| } | |
| # --- Database Initialization (PostgreSQL) --- | |
| # Only initialize if DATABASE_URL is available | |
| database_url = config_service.get("DATABASE_URL") | |
| if database_url and database_url != "your_database_dsn_here": | |
| try: | |
| db_service = await init_db_pool(database_url) | |
| fundaments["db"] = db_service | |
| logger.info("Database service initialized.") | |
| except Exception as e: | |
| logger.warning(f"Database initialization failed, continuing without DB: {e}") | |
| fundaments["db"] = None | |
| else: | |
| logger.info("No valid DATABASE_URL found, skipping database initialization.") | |
| fundaments["db"] = None | |
| # --- Encryption Initialization --- | |
| # Only initialize if both encryption keys are available | |
| master_key = config_service.get("MASTER_ENCRYPTION_KEY") | |
| persistent_salt = config_service.get("PERSISTENT_ENCRYPTION_SALT") | |
| if master_key and persistent_salt and master_key != "your_256_bit_key_here": | |
| try: | |
| encryption_service = Encryption(master_key=master_key, salt=persistent_salt) | |
| fundaments["encryption"] = encryption_service | |
| logger.info("Encryption service initialized.") | |
| except Exception as e: | |
| logger.warning(f"Encryption initialization failed, continuing without encryption: {e}") | |
| fundaments["encryption"] = None | |
| else: | |
| logger.info("Encryption keys not found or using defaults, skipping encryption initialization.") | |
| fundaments["encryption"] = None | |
| # --- Access Control Initialization --- | |
| # Only initialize if we have a database connection | |
| if fundaments["db"] is not None: | |
| try: | |
| access_control_service = AccessControl() | |
| fundaments["access_control"] = access_control_service | |
| logger.info("Access Control service initialized.") | |
| except Exception as e: | |
| logger.warning(f"Access Control initialization failed: {e}") | |
| fundaments["access_control"] = None | |
| else: | |
| logger.info("No database available, skipping Access Control initialization.") | |
| fundaments["access_control"] = None | |
| # --- User Handler Initialization --- | |
| # Only initialize if we have a database connection | |
| if fundaments["db"] is not None: | |
| try: | |
| user_handler_service = UserHandler(fundaments["db"]) | |
| fundaments["user_handler"] = user_handler_service | |
| logger.info("User Handler service initialized.") | |
| except Exception as e: | |
| logger.warning(f"User Handler initialization failed: {e}") | |
| fundaments["user_handler"] = None | |
| else: | |
| logger.info("No database available, skipping User Handler initialization.") | |
| fundaments["user_handler"] = None | |
| # --- Security Manager Initialization --- | |
| # Only initialize if we have the required sub-services | |
| available_services = {k: v for k, v in fundaments.items() if v is not None and k != "config"} | |
| if len(available_services) >= 1: # At least one service beyond config | |
| try: | |
| # Filter out None services for Security manager | |
| fundament_services = { | |
| k: v for k, v in { | |
| "user_handler": fundaments.get("user_handler"), | |
| "access_control": fundaments.get("access_control"), | |
| "encryption": fundaments.get("encryption") | |
| }.items() if v is not None | |
| } | |
| if fundament_services: # Only if we have actual services | |
| security_service = Security(fundament_services) | |
| fundaments["security"] = security_service | |
| logger.info("Security manager initialized.") | |
| else: | |
| logger.info("No services available for Security manager, skipping initialization.") | |
| fundaments["security"] = None | |
| except Exception as e: | |
| logger.warning(f"Security manager initialization failed: {e}") | |
| fundaments["security"] = None | |
| else: | |
| logger.info("Insufficient services for Security manager, skipping initialization.") | |
| fundaments["security"] = None | |
| # Log what was actually initialized | |
| initialized_services = [k for k, v in fundaments.items() if v is not None] | |
| logger.info(f"Successfully initialized services: {', '.join(initialized_services)}") | |
| return fundaments | |
| async def main(): | |
| """ | |
| The main asynchronous function of the application. | |
| """ | |
| logger.info("Starting main.py...") | |
| fundaments = await initialize_fundaments() | |
| try: | |
| # Load the actual app logic here. | |
| # This is where your 'app/app.py' would be imported and run. | |
| logger.info("Fundament modules are ready for the app logic.") | |
| # Example: | |
| from app.app import start_application | |
| await start_application(fundaments) | |
| finally: | |
| # Ensure the database pool is closed gracefully on exit (if it was initialized) | |
| if fundaments.get("db") is not None: | |
| await close_db_pool() | |
| logger.info("Database pool closed.") | |
| logger.info("Application shut down.") | |
| if __name__ == "__main__": | |
| asyncio.run(main()) | |