from flask import Flask, render_template_string, request, redirect, url_for, flash, jsonify import json import os # Added os import import subprocess # Added subprocess import from src.config_manager import ConfigManager app = Flask(__name__) app.secret_key = os.urandom(24) # Needed for flash messages config_manager = ConfigManager() CONFIG_PAGE_TEMPLATE = """ LED Matrix Config

LED Matrix Configuration

{% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% endif %} {% endwith %}

Main Configuration ({{ main_config_path }})

Secrets Configuration ({{ secrets_config_path }})

Display & Service Actions


Action Output:

No action run yet.
""" @app.route('/') def display_config_route(): active_tab = request.args.get('tab', 'main') # Default to 'main' tab main_config_data = {} secrets_config_data = {} error_message = None try: main_config_data = config_manager.get_raw_file_content('main') except Exception as e: flash(f"Error loading main config: {str(e)}", "error") try: secrets_config_data = config_manager.get_raw_file_content('secrets') except Exception as e: flash(f"Error loading secrets config: {str(e)}", "error") main_config_json = json.dumps(main_config_data, indent=4) secrets_config_json = json.dumps(secrets_config_data, indent=4) return render_template_string(CONFIG_PAGE_TEMPLATE, main_config_json=main_config_json, secrets_config_json=secrets_config_json, active_tab=active_tab, main_config_path=config_manager.get_config_path(), secrets_config_path=config_manager.get_secrets_path()) @app.route('/save', methods=['POST']) def save_config_route(): config_type = request.form.get('config_type', 'main') data_to_save_str = "" if config_type == 'main': data_to_save_str = request.form['main_config_data'] elif config_type == 'secrets': data_to_save_str = request.form['secrets_config_data'] else: flash("Invalid configuration type specified for saving.", "error") return redirect(url_for('display_config_route')) try: new_data = json.loads(data_to_save_str) config_manager.save_raw_file_content(config_type, new_data) flash(f"{config_type.capitalize()} configuration saved successfully!", "success") except json.JSONDecodeError: flash(f"Error: Invalid JSON format submitted for {config_type} config.", "error") except Exception as e: flash(f"Error saving {config_type} configuration: {str(e)}", "error") return redirect(url_for('display_config_route', tab=config_type)) # Redirect back to the same tab @app.route('/run_action', methods=['POST']) def run_action_route(): data = request.get_json() action = data.get('action') command_parts = [] # Use a list for subprocess explanation_msg = "" if action == 'start_display': command_parts = ["sudo", "python", "display_controller.py"] # Changed command explanation_msg = "Starts the LED matrix display by directly running display_controller.py with sudo." elif action == 'stop_display': command_parts = ["bash", "stop_display.sh"] explanation_msg = "Stops the LED matrix display by executing the stop_display.sh script." elif action == 'enable_autostart': command_parts = ["sudo", "systemctl", "enable", "ledmatrix.service"] explanation_msg = "Enables the LED matrix service to start automatically on boot." elif action == 'disable_autostart': command_parts = ["sudo", "systemctl", "disable", "ledmatrix.service"] explanation_msg = "Disables the LED matrix service from starting automatically on boot." else: return jsonify({ "status": "error", "message": "Invalid action specified.", "error": "Unknown action" }), 400 try: # Direct execution using subprocess process_result = subprocess.run(command_parts, capture_output=True, text=True, check=False) stdout_content = process_result.stdout stderr_content = process_result.stderr exit_code = process_result.returncode current_status = "success" message_to_user = f"Action '{action}' executed. Exit code: {exit_code}." if exit_code != 0: current_status = "error" message_to_user = f"Action '{action}' failed. Exit code: {exit_code}." elif stderr_content: # Even with exit code 0, stderr might contain warnings current_status = "warning" message_to_user = f"Action '{action}' executed with output in stderr (Exit code: {exit_code})." return jsonify({ "status": current_status, "message": message_to_user, "stdout": stdout_content, "stderr": stderr_content }) except FileNotFoundError as e: # This occurs if the command itself (e.g., 'bash', 'sudo', or the script) isn't found return jsonify({ "status": "error", "message": f"Error executing action '{action}': Command or script not found.", "error": str(e), "stdout": "", "stderr": f"Command not found: {command_parts[0] if command_parts else ''}" }), 500 except Exception as e: # Catch any other exceptions during subprocess execution or in this route return jsonify({ "status": "error", "message": f"An unexpected error occurred while processing action: {action}", "error": str(e) }), 500 if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)