import logging import queue import signal import sys import threading import time from src.config import load_config from src.summarizer import poll_accounts, process_email from src.tg_bot import poll_telegram logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", datefmt="%Y-%m-%d %H:%M:%S", ) logger = logging.getLogger("main") _running = True _pending_lock = threading.Lock() _pending_uids: set[bytes] = set() def _signal_handler(signum, frame): global _running logger.info("收到退出信号,正在停止...") _running = False def _email_poller(cfg, processing_queue): logger.info("邮件轮询线程已启动") while _running: for acct_idx, mail in poll_accounts(cfg): if not _running: return with _pending_lock: if mail.uid not in _pending_uids: _pending_uids.add(mail.uid) processing_queue.put((acct_idx, mail)) if _running: for _ in range(cfg.polling.interval_seconds): if not _running: return time.sleep(1) def _email_processor(cfg, processing_queue): logger.info("邮件处理线程已启动") while _running: try: acct_idx, mail = processing_queue.get(timeout=1) except queue.Empty: continue try: process_email(cfg, acct_idx, mail) except Exception as e: logger.error(f"处理邮件失败: {e}", exc_info=True) finally: with _pending_lock: _pending_uids.discard(mail.uid) def _tg_poller(cfg): logger.info("TG 轮询线程已启动") last_update_id = 0 while _running: try: last_update_id = poll_telegram(cfg.telegram, cfg, last_update_id) except Exception as e: logger.error(f"TG 轮询错误: {e}", exc_info=True) if _running: time.sleep(1) def main(): global _running signal.signal(signal.SIGINT, _signal_handler) signal.signal(signal.SIGTERM, _signal_handler) cfg_path = sys.argv[1] if len(sys.argv) > 1 else "config.yaml" cfg = load_config(cfg_path) logger.info(f"AI邮件摘要机器人已启动,轮询间隔: {cfg.polling.interval_seconds}s") processing_queue: queue.Queue = queue.Queue() threads = [ threading.Thread(target=_email_poller, args=(cfg, processing_queue), daemon=True), threading.Thread(target=_email_processor, args=(cfg, processing_queue), daemon=True), threading.Thread(target=_tg_poller, args=(cfg,), daemon=True), ] for t in threads: t.start() try: while _running: time.sleep(1) except KeyboardInterrupt: _running = False for t in threads: t.join(timeout=5) logger.info("机器人已停止") if __name__ == "__main__": main()