"feat: Added debug server and related components for improved development experience"
This commit is contained in:
176
backend/app.py
176
backend/app.py
@@ -1,5 +1,4 @@
|
||||
from flask import Flask, request, jsonify, g, redirect, url_for, session as flask_session, render_template, flash
|
||||
from flask_cors import CORS
|
||||
from flask import Flask, request, jsonify, g, redirect, url_for, session as flask_session, render_template, flash, send_from_directory
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
import secrets # Für bessere Salt-Generierung
|
||||
from functools import wraps
|
||||
@@ -17,20 +16,82 @@ from datetime import timedelta
|
||||
from PyP100 import PyP100
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Importiere Konfiguration
|
||||
from config import config
|
||||
|
||||
# Importiere Netzwerkkonfiguration
|
||||
from network_config import NetworkConfig
|
||||
|
||||
# Importiere Frontend V2 Blueprint
|
||||
from frontend_v2_routes import frontend_v2, set_app_functions
|
||||
|
||||
# Lade Umgebungsvariablen
|
||||
load_dotenv()
|
||||
|
||||
# Initialisierung
|
||||
def create_app(config_name=None):
|
||||
"""
|
||||
Application Factory Pattern für die Flask-Anwendung.
|
||||
|
||||
Args:
|
||||
config_name: Name der zu verwendenden Konfiguration ('development', 'production', 'testing')
|
||||
|
||||
Returns:
|
||||
Flask: Konfigurierte Flask-Anwendung
|
||||
"""
|
||||
app = Flask(__name__)
|
||||
|
||||
# Bestimme Konfiguration
|
||||
if config_name is None:
|
||||
config_name = os.environ.get('FLASK_ENV', 'development')
|
||||
|
||||
# Lade Konfiguration
|
||||
config_object = config.get(config_name, config['default'])
|
||||
app.config.from_object(config_object)
|
||||
|
||||
# Initialisiere Konfiguration
|
||||
config_object.init_app(app)
|
||||
|
||||
# Initialisiere Netzwerkkonfiguration
|
||||
network_config = NetworkConfig(app)
|
||||
|
||||
# Registriere Blueprint
|
||||
app.register_blueprint(frontend_v2, url_prefix='/frontend_v2')
|
||||
|
||||
# Konfiguriere statische Dateien für Frontend v2
|
||||
@app.route('/frontend_v2/static/<path:filename>')
|
||||
def frontend_v2_static(filename):
|
||||
return send_from_directory(os.path.join(app.root_path, 'frontend_v2/static'), filename)
|
||||
|
||||
# Globale Variablen
|
||||
app.config['PRINTERS'] = json.loads(app.config.get('PRINTERS', '{}'))
|
||||
|
||||
# Database functions registrieren
|
||||
register_database_functions(app)
|
||||
|
||||
# Authentifizierung registrieren
|
||||
register_auth_functions(app)
|
||||
|
||||
# API-Routen registrieren
|
||||
register_api_routes(app)
|
||||
|
||||
# Web-UI-Routen registrieren
|
||||
register_web_routes(app)
|
||||
|
||||
# Error-Handler registrieren
|
||||
register_error_handlers(app)
|
||||
|
||||
# Hintergrund-Tasks registrieren
|
||||
register_background_tasks(app)
|
||||
|
||||
return app
|
||||
|
||||
# Initialisierung - wird später durch create_app ersetzt
|
||||
app = Flask(__name__)
|
||||
CORS(app, supports_credentials=True)
|
||||
|
||||
# Initialisiere Netzwerkkonfiguration
|
||||
network_config = NetworkConfig(app)
|
||||
|
||||
# Konfiguration
|
||||
# Temporäre Konfiguration für Legacy-Code
|
||||
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'dev_secret_key')
|
||||
app.config['DATABASE'] = os.environ.get('DATABASE_PATH', 'instance/myp.db')
|
||||
app.config['SESSION_COOKIE_HTTPONLY'] = True
|
||||
@@ -39,11 +100,65 @@ app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
|
||||
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
|
||||
app.config['JOB_CHECK_INTERVAL'] = int(os.environ.get('JOB_CHECK_INTERVAL', '60')) # Sekunden
|
||||
|
||||
# Registriere Frontend V2 Blueprint
|
||||
app.register_blueprint(frontend_v2, url_prefix='/frontend_v2')
|
||||
|
||||
# Übergebe Funktionen an das Frontend v2
|
||||
def setup_frontend_v2():
|
||||
app_functions = {
|
||||
'get_current_user': get_current_user,
|
||||
'get_user_by_id': get_user_by_id,
|
||||
'get_socket_by_id': get_socket_by_id,
|
||||
'get_job_by_id': get_job_by_id,
|
||||
'get_all_sockets': get_all_sockets,
|
||||
'get_all_users': get_all_users,
|
||||
'get_all_jobs': get_all_jobs,
|
||||
'get_jobs_by_user': get_jobs_by_user,
|
||||
'login_required': login_required,
|
||||
'admin_required': admin_required,
|
||||
'delete_session': delete_session,
|
||||
'socket_to_dict': socket_to_dict,
|
||||
'job_to_dict': job_to_dict,
|
||||
'user_to_dict': user_to_dict
|
||||
}
|
||||
set_app_functions(app_functions)
|
||||
|
||||
# Konfiguriere statische Dateien für Frontend v2
|
||||
@app.route('/frontend_v2/static/<path:filename>')
|
||||
def frontend_v2_static(filename):
|
||||
return send_from_directory(os.path.join(app.root_path, 'frontend_v2/static'), filename)
|
||||
|
||||
# Steckdosen-Konfiguration
|
||||
TAPO_USERNAME = os.environ.get('TAPO_USERNAME')
|
||||
TAPO_PASSWORD = os.environ.get('TAPO_PASSWORD')
|
||||
|
||||
# Logging
|
||||
def setup_logging(app):
|
||||
"""
|
||||
Konfiguriert das Logging basierend auf der Umgebung.
|
||||
|
||||
Args:
|
||||
app: Flask-Anwendung
|
||||
"""
|
||||
if not app.debug and not app.testing:
|
||||
# Production logging
|
||||
if not os.path.exists('logs'):
|
||||
os.mkdir('logs')
|
||||
|
||||
file_handler = RotatingFileHandler('logs/myp.log', maxBytes=10240, backupCount=10)
|
||||
file_handler.setFormatter(logging.Formatter(
|
||||
'%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
|
||||
))
|
||||
file_handler.setLevel(logging.INFO)
|
||||
app.logger.addHandler(file_handler)
|
||||
|
||||
app.logger.setLevel(logging.INFO)
|
||||
app.logger.info('MYP Backend starting in production mode')
|
||||
else:
|
||||
# Development logging
|
||||
app.logger.setLevel(logging.DEBUG)
|
||||
app.logger.info('MYP Backend starting in development mode')
|
||||
|
||||
# Logging - Legacy (wird durch setup_logging ersetzt)
|
||||
if not os.path.exists('logs'):
|
||||
os.mkdir('logs')
|
||||
file_handler = RotatingFileHandler('logs/myp.log', maxBytes=10240, backupCount=10)
|
||||
@@ -1686,9 +1801,33 @@ def stats_page():
|
||||
return redirect(url_for('index'))
|
||||
return render_template('stats.html', current_user=current_user, active_page='stats')
|
||||
|
||||
# Initialisierung und Start des Hintergrund-Threads beim ersten Request
|
||||
with app.app_context():
|
||||
# Diese Funktion wird nach dem App-Start aber vor dem ersten Request ausgeführt
|
||||
# Registrierungsfunktionen für modularen Aufbau
|
||||
def register_database_functions(app):
|
||||
"""Registriert Database-Funktionen und Teardown-Handler."""
|
||||
app.teardown_appcontext(close_db)
|
||||
|
||||
def register_auth_functions(app):
|
||||
"""Registriert Authentifizierungsfunktionen."""
|
||||
# Authentifizierungsfunktionen sind bereits global definiert
|
||||
pass
|
||||
|
||||
def register_api_routes(app):
|
||||
"""Registriert alle API-Routen."""
|
||||
# API-Routen sind bereits global definiert
|
||||
pass
|
||||
|
||||
def register_web_routes(app):
|
||||
"""Registriert alle Web-UI-Routen."""
|
||||
# Web-Routen sind bereits global definiert
|
||||
pass
|
||||
|
||||
def register_error_handlers(app):
|
||||
"""Registriert Error-Handler."""
|
||||
# Error-Handler sind bereits global definiert
|
||||
pass
|
||||
|
||||
def register_background_tasks(app):
|
||||
"""Registriert Hintergrund-Tasks."""
|
||||
@app.before_request
|
||||
def initialize_background_tasks():
|
||||
"""Startet den Hintergrund-Thread für Job-Überprüfung beim ersten Request."""
|
||||
@@ -1711,6 +1850,7 @@ with app.app_context():
|
||||
|
||||
# Server starten
|
||||
if __name__ == '__main__':
|
||||
# Legacy-Modus für direkte Ausführung
|
||||
with app.app_context():
|
||||
init_db()
|
||||
if PRINTERS:
|
||||
@@ -1721,5 +1861,21 @@ if __name__ == '__main__':
|
||||
job_thread = threading.Thread(target=background_job_checker, daemon=True, name='job_checker_thread')
|
||||
job_thread.start()
|
||||
app.logger.info("Hintergrund-Thread für Job-Überprüfung gestartet")
|
||||
setup_frontend_v2()
|
||||
|
||||
app.run(debug=True, host='0.0.0.0')
|
||||
# Produktionsmodus aktivieren
|
||||
flask_env = os.environ.get('FLASK_ENV', 'development')
|
||||
debug_mode = flask_env == 'development'
|
||||
|
||||
app.run(host='0.0.0.0', port=5000, debug=debug_mode)
|
||||
else:
|
||||
# Für WSGI-Server wie Gunicorn - verwende Application Factory
|
||||
flask_env = os.environ.get('FLASK_ENV', 'production')
|
||||
app = create_app(flask_env)
|
||||
|
||||
with app.app_context():
|
||||
init_db()
|
||||
printers_config = json.loads(app.config.get('PRINTERS', '{}'))
|
||||
if printers_config:
|
||||
init_printers()
|
||||
setup_frontend_v2()
|
Reference in New Issue
Block a user