feat: add account run history module and logging functionality

- Implemented `background/account-run-history.js` to persist account run results (success, failure, stop) in `chrome.storage.local` and log to a text file when the local Hotmail helper is enabled.
- Enhanced `background/auto-run-controller.js` and `background/message-router.js` to utilize the new account run record functionality.
- Updated steps in `background/steps/fetch-login-code.js`, `background/steps/fetch-signup-code.js`, and `background/steps/oauth-login.js` to handle retries and logging appropriately.
- Introduced tests for account run history and step retry limits to ensure functionality and reliability.
- Modified documentation to reflect new features and changes in behavior for specific providers (e.g., 2925).
This commit is contained in:
QLHazyCoder
2026-04-17 02:52:26 +08:00
parent e48941806f
commit 6652899758
15 changed files with 858 additions and 67 deletions
+41
View File
@@ -2,8 +2,11 @@ import email
import html
import imaplib
import json
import os
import re
import threading
import time
import traceback
from datetime import datetime, timezone
from email.header import decode_header
from email.utils import parseaddr, parsedate_to_datetime
@@ -59,6 +62,9 @@ IMAP_HOST = "outlook.office365.com"
IMAP_PORT = 993
REQUEST_TIMEOUT_SECONDS = 45
FETCH_LIMIT_DEFAULT = 5
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
ACCOUNT_LOG_PATH = os.path.join(BASE_DIR, "data", "account-run-history.txt")
ACCOUNT_LOG_LOCK = threading.Lock()
def json_response(handler, status, payload):
@@ -113,6 +119,24 @@ def log_info(message):
print(f"[HotmailHelper] {message}", flush=True)
def append_account_log(email_addr, password, status, recorded_at="", reason=""):
normalized_email = str(email_addr or "").strip()
normalized_password = str(password or "").strip()
normalized_status = str(status or "").strip().lower()
normalized_recorded_at = str(recorded_at or "").strip() or datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
normalized_reason = str(reason or "").strip().replace("\r", " ").replace("\n", " ")
if not normalized_email or not normalized_password or not normalized_status:
raise RuntimeError("Missing email/password/status for account log append")
os.makedirs(os.path.dirname(ACCOUNT_LOG_PATH), exist_ok=True)
line = f"{normalized_recorded_at}\t{normalized_email}\t{normalized_password}\t{normalized_status}\t{normalized_reason}\n"
with ACCOUNT_LOG_LOCK:
with open(ACCOUNT_LOG_PATH, "a", encoding="utf-8") as handle:
handle.write(line)
return ACCOUNT_LOG_PATH
def try_refresh_access_token(endpoint, client_id, refresh_token):
request_data = {
"client_id": client_id,
@@ -600,6 +624,21 @@ class HotmailHelperHandler(BaseHTTPRequestHandler):
def do_POST(self):
try:
payload = read_json_payload(self)
if self.path == "/append-account-log":
file_path = append_account_log(
payload.get("email"),
payload.get("password"),
payload.get("status"),
payload.get("recordedAt"),
payload.get("reason"),
)
json_response(self, 200, {
"ok": True,
"filePath": file_path,
})
return
email_addr = str(payload.get("email") or "").strip()
client_id = str(payload.get("clientId") or "").strip()
refresh_token = str(payload.get("refreshToken") or "").strip()
@@ -643,12 +682,14 @@ class HotmailHelperHandler(BaseHTTPRequestHandler):
json_response(self, 404, {"ok": False, "error": f"Unsupported path: {self.path}"})
except Exception as exc:
traceback.print_exc()
json_response(self, 500, {"ok": False, "error": str(exc)})
def main():
server = ThreadingHTTPServer((HOST, PORT), HotmailHelperHandler)
print(f"Hotmail helper listening on http://{HOST}:{PORT}", flush=True)
print(f"Account log file: {ACCOUNT_LOG_PATH}", flush=True)
try:
server.serve_forever()
except KeyboardInterrupt: