""" MyICR Suite — Flask server (porta 5001) Serve la welcome page e le API di lancio moduli. """ import os import sys import subprocess from pathlib import Path from flask import Flask, jsonify, send_from_directory _SUITE_DIR = Path(__file__).resolve().parent # .../app/suite/ _APP_ROOT = _SUITE_DIR.parent.parent # .../MyICR_Suite/ _FRONTEND = _SUITE_DIR / 'frontend' app = Flask(__name__, static_folder=None) # Processi figli attivi — evita lanci multipli _procs: dict = {} def _python_exe() -> Path: """Restituisce il Python corrente (pythonw.exe in produzione, python.exe in dev).""" return Path(sys.executable) def terminate_all_subprocesses(): for proc in list(_procs.values()): if proc.poll() is None: proc.terminate() _procs.clear() def _launch_subprocess(name: str, script: Path, extra_args: list = None) -> dict: existing = _procs.get(name) if existing is not None and existing.poll() is None: return {'ok': False, 'error': f'{name} è già in esecuzione'} cmd = [str(_python_exe()), str(script)] + (extra_args or []) flags = subprocess.CREATE_NO_WINDOW if sys.platform == 'win32' else 0 try: proc = subprocess.Popen(cmd, cwd=str(_APP_ROOT), creationflags=flags) _procs[name] = proc if sys.platform == 'win32': try: import ctypes ctypes.windll.user32.AllowSetForegroundWindow(proc.pid) except Exception: pass return {'ok': True} except Exception as e: return {'ok': False, 'error': str(e)} # ------------------------------------------------------------------ routes @app.route('/') def index(): return send_from_directory(str(_FRONTEND), 'welcome.html') @app.route('/static/') def static_files(filename): return send_from_directory(str(_FRONTEND), filename) @app.route('/api/version') def api_version(): try: from app.config_loader import get_version return jsonify({'version': get_version()}) except Exception: return jsonify({'version': ''}) def _current_user() -> str: return os.environ.get('USERNAME', '').lower() def _report_reti_allowed() -> bool: try: from app.config_loader import load_config allowed = [u.lower() for u in load_config().get('report_reti_users', [])] return _current_user() in allowed except Exception: return False @app.route('/api/config') def api_config(): return jsonify({ 'dev_mode': os.environ.get('MYICR_DEV_MODE') == '1', 'can_report_reti': _report_reti_allowed(), }) @app.route('/api/launch/mediatrack', methods=['POST']) def launch_mediatrack(): script = _APP_ROOT / 'app' / 'modules' / 'mediatrack' / 'run.py' return jsonify(_launch_subprocess('mediatrack', script)) @app.route('/api/launch/linker', methods=['POST']) def launch_linker(): script = _APP_ROOT / 'app' / 'modules' / 'linker' / 'run.py' return jsonify(_launch_subprocess('linker', script)) @app.route('/api/launch/report_reti', methods=['POST']) def launch_report_reti(): script = _APP_ROOT / 'app' / 'modules' / 'report_reti' / 'run.py' return jsonify(_launch_subprocess('report_reti', script)) _DASH_SCRIPTS = { 'tipologie': _APP_ROOT / 'app' / 'features' / 'dash_tipologie' / 'run.py', 'pivot': _APP_ROOT / 'app' / 'features' / 'dash_em_pivot' / 'run.py', 'diritti': _APP_ROOT / 'app' / 'features' / 'dash_diritti' / 'run.py', } @app.route('/api/launch/dash/', methods=['POST']) def launch_dash(name): script = _DASH_SCRIPTS.get(name) if script is None: return jsonify({'ok': False, 'error': f'Dashboard "{name}" non riconosciuta'}) return jsonify(_launch_subprocess(f'dash_{name}', script))