mirror of
https://github.com/cnlimiter/codex-register.git
synced 2026-05-06 20:02:51 +08:00
feat(email): update email polling logic to use configurable intervals
This commit is contained in:
@@ -37,7 +37,7 @@ from ..config.settings import get_settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
OTP_SECONDARY_TIMEOUT_SECONDS = 120
|
||||
OTP_SECONDARY_TIMEOUT_SECONDS = 120 # 默认值,运行时由 get_settings().email_code_timeout 覆盖
|
||||
PHASE_EMAIL_PREPARE = "email_prepare"
|
||||
PHASE_OTP_SECONDARY = "otp_secondary"
|
||||
ERROR_EMAIL_PROVIDER_RATE_LIMITED = "EMAIL_PROVIDER_RATE_LIMITED"
|
||||
@@ -646,7 +646,7 @@ class RegistrationEngine:
|
||||
|
||||
email_id = self.email_info.get("service_id") if self.email_info else None
|
||||
budget = Budget(
|
||||
timeout_seconds=OTP_SECONDARY_TIMEOUT_SECONDS,
|
||||
timeout_seconds=get_settings().email_code_timeout,
|
||||
started_at=started_at if started_at is not None else time.time(),
|
||||
)
|
||||
remaining_timeout = budget.remaining_seconds()
|
||||
|
||||
@@ -13,11 +13,21 @@ from typing import Optional, Dict, Any, List
|
||||
from enum import Enum
|
||||
|
||||
from ..config.constants import EmailServiceType, OTP_CODE_PATTERN, OTP_CODE_SEMANTIC_PATTERN
|
||||
from ..config.settings import get_settings
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
EMAIL_PROVIDER_BACKOFF_BASE_SECONDS = 30
|
||||
|
||||
|
||||
def get_email_code_settings() -> dict:
|
||||
"""获取验证码等待配置(timeout、poll_interval)"""
|
||||
settings = get_settings()
|
||||
return {
|
||||
"timeout": settings.email_code_timeout,
|
||||
"poll_interval": settings.email_code_poll_interval,
|
||||
}
|
||||
EMAIL_PROVIDER_BACKOFF_MAX_SECONDS = 3600
|
||||
OTP_TIMEOUT_ERROR_PREFIX = "OTP_TIMEOUT"
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import time
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError, get_email_code_settings
|
||||
from ..config.constants import OTP_CODE_PATTERN
|
||||
from ..core.http_client import HTTPClient, RequestConfig
|
||||
|
||||
@@ -231,6 +231,7 @@ class CloudMailService(BaseEmailService):
|
||||
) -> Optional[str]:
|
||||
logger.info(f"正在从 Cloud Mail 邮箱 {email} 获取验证码...")
|
||||
|
||||
poll_interval = get_email_code_settings()["poll_interval"]
|
||||
start_time = time.time()
|
||||
seen_mail_ids: set = set()
|
||||
|
||||
@@ -252,7 +253,7 @@ class CloudMailService(BaseEmailService):
|
||||
mails = mails["list"]
|
||||
|
||||
if not isinstance(mails, list):
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
continue
|
||||
|
||||
for mail in mails:
|
||||
@@ -288,7 +289,7 @@ class CloudMailService(BaseEmailService):
|
||||
except Exception as e:
|
||||
logger.debug(f"检查 Cloud Mail 邮件时出错: {e}")
|
||||
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
|
||||
logger.warning(f"等待 Cloud Mail 验证码超时: {email}")
|
||||
return None
|
||||
|
||||
@@ -12,7 +12,7 @@ from datetime import datetime, timezone
|
||||
from html import unescape
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError, get_email_code_settings
|
||||
from ..config.constants import OTP_CODE_PATTERN
|
||||
from ..core.http_client import HTTPClient, RequestConfig
|
||||
|
||||
@@ -258,6 +258,7 @@ class DuckMailService(BaseEmailService):
|
||||
logger.warning(f"DuckMail 邮箱缺少访问 token: {email}")
|
||||
return None
|
||||
|
||||
poll_interval = get_email_code_settings()["poll_interval"]
|
||||
start_time = time.time()
|
||||
seen_message_ids = set()
|
||||
|
||||
@@ -307,7 +308,7 @@ class DuckMailService(BaseEmailService):
|
||||
except Exception as e:
|
||||
logger.debug(f"DuckMail 轮询验证码失败: {e}")
|
||||
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import random
|
||||
import string
|
||||
from typing import Optional, Dict, Any, List
|
||||
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError, get_email_code_settings
|
||||
from ..core.http_client import HTTPClient, RequestConfig
|
||||
from ..config.constants import OTP_CODE_PATTERN
|
||||
|
||||
@@ -211,6 +211,7 @@ class FreemailService(BaseEmailService):
|
||||
"""
|
||||
logger.info(f"正在从 Freemail 邮箱 {email} 获取验证码...")
|
||||
|
||||
poll_interval = get_email_code_settings()["poll_interval"]
|
||||
start_time = time.time()
|
||||
seen_mail_ids: set = set()
|
||||
|
||||
@@ -218,7 +219,7 @@ class FreemailService(BaseEmailService):
|
||||
try:
|
||||
mails = self._make_request("GET", "/api/emails", params={"mailbox": email, "limit": 20})
|
||||
if not isinstance(mails, list):
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
continue
|
||||
|
||||
ordered_mails = self._sort_items_by_message_time(
|
||||
@@ -287,7 +288,7 @@ class FreemailService(BaseEmailService):
|
||||
except Exception as e:
|
||||
logger.debug(f"检查 Freemail 邮件时出错: {e}")
|
||||
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
|
||||
logger.warning(f"等待 Freemail 验证码超时: {email}")
|
||||
return None
|
||||
|
||||
@@ -12,7 +12,7 @@ import logging
|
||||
from email.header import decode_header
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from .base import BaseEmailService, EmailServiceError
|
||||
from .base import BaseEmailService, EmailServiceError, get_email_code_settings
|
||||
from ..config.constants import (
|
||||
EmailServiceType,
|
||||
OPENAI_EMAIL_SENDERS,
|
||||
@@ -123,6 +123,7 @@ class ImapMailService(BaseEmailService):
|
||||
otp_sent_at: Optional[float] = None,
|
||||
) -> Optional[str]:
|
||||
"""轮询 IMAP 收件箱,获取 OpenAI 验证码"""
|
||||
poll_interval = get_email_code_settings()["poll_interval"]
|
||||
start_time = time.time()
|
||||
seen_ids: set = set()
|
||||
mail = None
|
||||
@@ -136,7 +137,7 @@ class ImapMailService(BaseEmailService):
|
||||
# 搜索所有未读邮件
|
||||
status, data = mail.search(None, "UNSEEN")
|
||||
if status != "OK" or not data or not data[0]:
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
continue
|
||||
|
||||
msg_ids = data[0].split()
|
||||
@@ -177,7 +178,7 @@ class ImapMailService(BaseEmailService):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"IMAP 连接/轮询失败: {e}")
|
||||
|
||||
@@ -10,7 +10,7 @@ import logging
|
||||
from typing import Optional, Dict, Any, List
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError, get_email_code_settings
|
||||
from ..core.http_client import HTTPClient, RequestConfig
|
||||
from ..config.constants import OTP_CODE_PATTERN
|
||||
|
||||
@@ -303,6 +303,7 @@ class MeoMailEmailService(BaseEmailService):
|
||||
|
||||
logger.info(f"正在从自定义域名邮箱 {email} 获取验证码...")
|
||||
|
||||
poll_interval = get_email_code_settings()["poll_interval"]
|
||||
start_time = time.time()
|
||||
seen_message_ids = set()
|
||||
|
||||
@@ -313,7 +314,7 @@ class MeoMailEmailService(BaseEmailService):
|
||||
|
||||
messages = response.get("messages", [])
|
||||
if not isinstance(messages, list):
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
continue
|
||||
|
||||
ordered_messages = self._sort_items_by_message_time(
|
||||
@@ -370,7 +371,7 @@ class MeoMailEmailService(BaseEmailService):
|
||||
logger.debug(f"检查邮件时出错: {e}")
|
||||
|
||||
# 等待一段时间再检查
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
|
||||
logger.warning(f"等待验证码超时: {email}")
|
||||
return None
|
||||
|
||||
@@ -8,9 +8,8 @@ import threading
|
||||
import time
|
||||
from typing import Optional, Dict, Any, List
|
||||
|
||||
from ..base import BaseEmailService, EmailServiceError, EmailServiceStatus, EmailServiceType
|
||||
from ..base import BaseEmailService, EmailServiceError, EmailServiceStatus, EmailServiceType, get_email_code_settings
|
||||
from ...config.constants import EmailServiceType as ServiceType
|
||||
from ...config.settings import get_settings
|
||||
from .account import OutlookAccount
|
||||
from .base import ProviderType, EmailMessage
|
||||
from .email_parser import EmailParser, get_email_parser
|
||||
@@ -34,15 +33,6 @@ DEFAULT_PROVIDER_PRIORITY = [
|
||||
]
|
||||
|
||||
|
||||
def get_email_code_settings() -> dict:
|
||||
"""获取验证码等待配置"""
|
||||
settings = get_settings()
|
||||
return {
|
||||
"timeout": settings.email_code_timeout,
|
||||
"poll_interval": settings.email_code_poll_interval,
|
||||
}
|
||||
|
||||
|
||||
class OutlookService(BaseEmailService):
|
||||
"""
|
||||
Outlook 邮箱服务
|
||||
|
||||
@@ -20,7 +20,7 @@ from email.header import decode_header
|
||||
from email.utils import parsedate_to_datetime
|
||||
from urllib.error import HTTPError
|
||||
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType, get_email_code_settings
|
||||
from ..config.constants import (
|
||||
OTP_CODE_PATTERN,
|
||||
OTP_CODE_SIMPLE_PATTERN,
|
||||
@@ -28,21 +28,6 @@ from ..config.constants import (
|
||||
OPENAI_EMAIL_SENDERS,
|
||||
OPENAI_VERIFICATION_KEYWORDS,
|
||||
)
|
||||
from ..config.settings import get_settings
|
||||
|
||||
|
||||
def get_email_code_settings() -> dict:
|
||||
"""
|
||||
获取验证码等待配置
|
||||
|
||||
Returns:
|
||||
dict: 包含 timeout 和 poll_interval 的字典
|
||||
"""
|
||||
settings = get_settings()
|
||||
return {
|
||||
"timeout": settings.email_code_timeout,
|
||||
"poll_interval": settings.email_code_poll_interval,
|
||||
}
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -15,7 +15,7 @@ from email.policy import default as email_policy
|
||||
from html import unescape
|
||||
from typing import Optional, Dict, Any, List
|
||||
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError, get_email_code_settings
|
||||
from ..core.http_client import HTTPClient, RequestConfig
|
||||
from ..config.constants import OTP_CODE_PATTERN
|
||||
|
||||
@@ -307,6 +307,7 @@ class TempMailService(BaseEmailService):
|
||||
logger.info(f"正在从 TempMail 邮箱 {email} 获取验证码...")
|
||||
|
||||
start_time = time.time()
|
||||
poll_interval = get_email_code_settings()["poll_interval"]
|
||||
seen_mail_ids: set = set()
|
||||
|
||||
# 优先使用用户级 JWT,回退到 admin API 先注释用户级API
|
||||
@@ -332,7 +333,7 @@ class TempMailService(BaseEmailService):
|
||||
# /user_api/mails 和 /admin/mails 返回格式相同: {"results": [...], "total": N}
|
||||
mails = response.get("results", [])
|
||||
if not isinstance(mails, list):
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
continue
|
||||
|
||||
ordered_mails = self._sort_items_by_message_time(
|
||||
@@ -381,7 +382,7 @@ class TempMailService(BaseEmailService):
|
||||
except Exception as e:
|
||||
logger.debug(f"检查 TempMail 邮件时出错: {e}")
|
||||
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
|
||||
logger.warning(f"等待 TempMail 验证码超时: {email}")
|
||||
return None
|
||||
|
||||
@@ -8,7 +8,7 @@ import logging
|
||||
from typing import Optional, Dict, Any, List
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType
|
||||
from .base import BaseEmailService, EmailServiceError, EmailServiceType, get_email_code_settings
|
||||
from ..core.http_client import HTTPClient, RequestConfig
|
||||
from ..config.constants import OTP_CODE_PATTERN
|
||||
|
||||
@@ -212,6 +212,7 @@ class TempmailService(BaseEmailService):
|
||||
|
||||
logger.info(f"正在等待邮箱 {email} 的验证码...")
|
||||
|
||||
poll_interval = get_email_code_settings()["poll_interval"]
|
||||
start_time = time.time()
|
||||
seen_ids = set()
|
||||
|
||||
@@ -225,7 +226,7 @@ class TempmailService(BaseEmailService):
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
continue
|
||||
|
||||
data = response.json()
|
||||
@@ -238,7 +239,7 @@ class TempmailService(BaseEmailService):
|
||||
email_list = data.get("emails", []) if isinstance(data, dict) else []
|
||||
|
||||
if not isinstance(email_list, list):
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
continue
|
||||
|
||||
ordered_emails = self._sort_items_by_message_time(
|
||||
@@ -292,7 +293,7 @@ class TempmailService(BaseEmailService):
|
||||
logger.debug(f"检查邮件时出错: {e}")
|
||||
|
||||
# 等待一段时间再检查
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
|
||||
logger.warning(f"等待验证码超时: {email}")
|
||||
return None
|
||||
@@ -384,6 +385,7 @@ class TempmailService(BaseEmailService):
|
||||
Returns:
|
||||
验证码或 None
|
||||
"""
|
||||
poll_interval = get_email_code_settings()["poll_interval"]
|
||||
start_time = time.time()
|
||||
seen_ids = set()
|
||||
check_count = 0
|
||||
@@ -402,7 +404,7 @@ class TempmailService(BaseEmailService):
|
||||
try:
|
||||
data = self.get_inbox(token)
|
||||
if not data:
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
continue
|
||||
|
||||
# 检查 inbox 是否过期
|
||||
@@ -465,7 +467,7 @@ class TempmailService(BaseEmailService):
|
||||
"message": "检查邮件时出错"
|
||||
})
|
||||
|
||||
time.sleep(3)
|
||||
time.sleep(poll_interval)
|
||||
|
||||
if callback:
|
||||
callback({
|
||||
|
||||
@@ -559,7 +559,7 @@ MyProxy|socks5://user:pass@host:port"></textarea>
|
||||
<div class="card" style="margin-top: var(--spacing-lg);">
|
||||
<div class="card-header">
|
||||
<h3>验证码等待配置</h3>
|
||||
<span class="hint">配置 Outlook 邮箱验证码获取的超时时间和轮询间隔</span>
|
||||
<span class="hint">配置验证码获取的超时时间和轮询间隔</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="email-code-form">
|
||||
|
||||
Reference in New Issue
Block a user