from sfm.config_loader import get_config from sfm.db import init_db from sfm.db_news import cleanup_old_news from sfm.db_sources import get_source, sync_config_sources from sfm.news_fetcher import fetch_news, fetch_source from sfm.digest import run_digests from sfm.watchdog import JOB_DIGEST, JOB_FETCH, notify_admin, run_watchdog, tracked, weekly_summary from sfm.logger import log, cleanup_logs from sfm.telegram_commands import start_telegram_listener import schedule import time import traceback # === Configurazione iniziale === init_db() CONFIG = get_config() MACHINE_NAME = CONFIG["machine_name"] DAILY_REPORT_TIME = CONFIG["daily_report_time"] CLEANUP_DAYS = CONFIG["data_retention_days"] POLLING_MINUTES = CONFIG["polling_minutes"] n_sources, new_source_ids = sync_config_sources(CONFIG["sites"]) log(f"🔄 Servizio avviato su {MACHINE_NAME} ({n_sources} fonti da config).") # Fonti appena aggiunte in config: prima lettura senza notifiche, per non # inviare una raffica di alert sulle notizie già pubblicate. for sid in new_source_ids: source = get_source(sid) try: seeded = fetch_source(source, notify=False) log(f"🌱 Fonte nuova '{source['name']}': salvate {seeded} notizie senza notifica.") except Exception as e: log(f"❌ Errore nella lettura iniziale di '{source['name']}': {e}") # === Scheduler === schedule.every(POLLING_MINUTES).minutes.do(tracked(JOB_FETCH, fetch_news)) schedule.every(1).minutes.do(tracked(JOB_DIGEST, run_digests)) # digest all'orario di ogni utente (default DAILY_REPORT_TIME) schedule.every(30).minutes.do(tracked("watchdog", run_watchdog)) # avvisa l'admin se fonti o job si rompono schedule.every().monday.at("08:00").do(tracked("weekly_summary", weekly_summary)) schedule.every().day.at("20:00").do(lambda: cleanup_logs(CLEANUP_DAYS)) schedule.every().day.at("20:30").do(lambda: cleanup_old_news(CLEANUP_DAYS)) # N.B. si fa riferimento alla data di fetch # === Listener Telegram === start_telegram_listener() # Avviso di avvio solo all'admin (gli utenti non devono vedere i riavvii) notify_admin(f"🔄 Servizio avviato su {MACHINE_NAME}", [f"{n_sources} fonti da config"]) # Primo fetch subito all'avvio, senza attendere il primo intervallo # (tracked cattura e logga eventuali errori) tracked(JOB_FETCH, fetch_news)() while True: try: schedule.run_pending() time.sleep(60) # Controlla ogni minuto except Exception as e: err = traceback.format_exc() log(f"❌ Errore nel loop principale: {e}\n{err}") notify_admin("❌ Errore nel loop principale", [str(e)]) time.sleep(10)