feat: 综合平台services多服务支持+SW网络优先缓存修复+适配层/定时任务完善
This commit is contained in:
@@ -39,5 +39,25 @@ class Settings:
|
||||
# ---- 续费提醒 ----
|
||||
RENEWAL_THRESHOLD_DAYS: int = int(os.getenv("RENEWAL_THRESHOLD_DAYS", "30"))
|
||||
|
||||
# ---- 监控数据保留策略(自动清理)----
|
||||
# MetricPoint 时序数据保留天数(Agent 高频上报,默认 30 天)
|
||||
METRICS_RETENTION_DAYS: int = int(os.getenv("METRICS_RETENTION_DAYS", "30"))
|
||||
# SecurityCheck 安全检查历史保留天数(默认 90 天)
|
||||
SECURITY_RETENTION_DAYS: int = int(os.getenv("SECURITY_RETENTION_DAYS", "90"))
|
||||
# EventLog 事件日志保留天数(默认 180 天)
|
||||
EVENT_LOG_RETENTION_DAYS: int = int(os.getenv("EVENT_LOG_RETENTION_DAYS", "180"))
|
||||
# 自动清理间隔(小时),0 表示禁用后台自动清理
|
||||
CLEANUP_INTERVAL_HOURS: int = int(os.getenv("CLEANUP_INTERVAL_HOURS", "24"))
|
||||
|
||||
# ---- Agent 上报频率限制 ----
|
||||
# 同一 asset_id 两次上报的最小间隔(秒),0 表示不限制
|
||||
AGENT_REPORT_MIN_INTERVAL: int = int(os.getenv("AGENT_REPORT_MIN_INTERVAL", "30"))
|
||||
|
||||
# ---- CORS 允许来源(逗号分隔),默认本地 + Tailscale ----
|
||||
CORS_ORIGINS: str = os.getenv(
|
||||
"CORS_ORIGINS",
|
||||
"http://127.0.0.1:8000,http://localhost:8000,https://dify.taile5765c.ts.net",
|
||||
)
|
||||
|
||||
|
||||
settings = Settings()
|
||||
|
||||
+3
-1
@@ -4,6 +4,7 @@
|
||||
MASTER_KEY 从 .env 读取,不入库。
|
||||
"""
|
||||
|
||||
from functools import lru_cache
|
||||
from typing import Optional
|
||||
|
||||
from cryptography.fernet import Fernet, InvalidToken
|
||||
@@ -11,8 +12,9 @@ from cryptography.fernet import Fernet, InvalidToken
|
||||
from app.core.config import settings
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _get_fernet() -> Fernet:
|
||||
"""获取 Fernet 实例(MASTER_KEY 未配置时抛错)"""
|
||||
"""获取 Fernet 实例(进程内缓存,避免每次加解密重建;MASTER_KEY 未配置时抛错)"""
|
||||
key = settings.MASTER_KEY
|
||||
if not key:
|
||||
raise RuntimeError(
|
||||
|
||||
+27
-6
@@ -10,57 +10,78 @@ from app.models.provider import Provider
|
||||
|
||||
PRESET_PROVIDERS = [
|
||||
# ---- VPS / 云服务商 ----
|
||||
# 综合平台:services 列出可提供的服务,卡片上会显示多标签
|
||||
{"slug": "aliyun", "name": "阿里云", "name_en": "Aliyun", "category": "vps",
|
||||
"services": "vps,domain,ssl_cert,cdn,dns",
|
||||
"website": "https://aliyun.com", "console_url": "https://ecs.console.aliyun.com", "sdk_type": "aliyun-sdk"},
|
||||
{"slug": "tencent", "name": "腾讯云", "name_en": "Tencent Cloud", "category": "vps",
|
||||
"services": "vps,domain,ssl_cert,cdn,dns",
|
||||
"website": "https://cloud.tencent.com", "console_url": "https://console.cloud.tencent.com/cvm", "sdk_type": "tencent-sdk"},
|
||||
{"slug": "aliyun-intl", "name": "阿里国际", "name_en": "Alibaba Cloud", "category": "vps",
|
||||
"services": "vps,domain,ssl_cert,cdn,dns",
|
||||
"website": "https://alibabacloud.com", "console_url": "https://ecs.console.alibabacloud.com", "sdk_type": "alibabacloud-sdk"},
|
||||
{"slug": "tencent-intl", "name": "腾讯国际", "name_en": "Tencent Cloud Intl", "category": "vps",
|
||||
"services": "vps,domain,ssl_cert,cdn,dns",
|
||||
"website": "https://intl.cloud.tencent.com", "console_url": "https://console.intl.cloud.tencent.com", "sdk_type": "tencent-intl-sdk"},
|
||||
{"slug": "vultr", "name": "Vultr", "name_en": "Vultr", "category": "vps",
|
||||
"services": "vps",
|
||||
"website": "https://vultr.com", "console_url": "https://my.vultr.com", "sdk_type": "vultr-api"},
|
||||
{"slug": "digitalocean", "name": "DigitalOcean", "name_en": "DigitalOcean", "category": "vps",
|
||||
"services": "vps,domain",
|
||||
"website": "https://digitalocean.com", "console_url": "https://cloud.digitalocean.com", "sdk_type": "do-api"},
|
||||
{"slug": "linode", "name": "Linode", "name_en": "Akamai Linode", "category": "vps",
|
||||
"services": "vps",
|
||||
"website": "https://linode.com", "console_url": "https://cloud.linode.com", "sdk_type": "linode-api"},
|
||||
{"slug": "cloudcone", "name": "CloudCone", "name_en": "CloudCone", "category": "vps",
|
||||
"services": "vps",
|
||||
"website": "https://cloudcone.com", "console_url": "https://app.cloudcone.com", "sdk_type": "cloudcone-api"},
|
||||
{"slug": "zeabur", "name": "Zeabur", "name_en": "Zeabur", "category": "vps",
|
||||
"services": "vps,domain",
|
||||
"website": "https://zeabur.com", "console_url": "https://dash.zeabur.com", "sdk_type": "zeabur-api"},
|
||||
# ---- 域名注册商 ----
|
||||
{"slug": "namesilo", "name": "Namesilo", "name_en": "Namesilo", "category": "domain",
|
||||
"services": "domain,dns",
|
||||
"website": "https://namesilo.com", "console_url": "https://www.namesilo.com/account_domains.php", "sdk_type": "namesilo-api"},
|
||||
{"slug": "xinwang", "name": "新网", "name_en": "Xinnet", "category": "domain",
|
||||
"services": "domain,dns",
|
||||
"website": "https://xinnet.com", "console_url": "https://www.xinnet.com", "sdk_type": None},
|
||||
{"slug": "dynadot", "name": "Dynadot", "name_en": "Dynadot", "category": "domain",
|
||||
"services": "domain,dns",
|
||||
"website": "https://dynadot.com", "console_url": "https://www.dynadot.com/account/domains", "sdk_type": "dynadot-api"},
|
||||
# ---- AI 服务商 ----
|
||||
{"slug": "openai", "name": "OpenAI", "name_en": "OpenAI", "category": "ai_agent",
|
||||
"services": "ai_agent",
|
||||
"website": "https://openai.com", "console_url": "https://platform.openai.com", "sdk_type": "openai-api"},
|
||||
{"slug": "minimax", "name": "Minimax", "name_en": "Minimax", "category": "ai_agent",
|
||||
"services": "ai_agent",
|
||||
"website": "https://minimax.io", "console_url": "https://platform.minimaxi.com", "sdk_type": "minimax-api"},
|
||||
{"slug": "kimi", "name": "Kimi", "name_en": "Moonshot", "category": "ai_agent",
|
||||
"services": "ai_agent",
|
||||
"website": "https://moonshot.cn", "console_url": "https://platform.moonshot.cn", "sdk_type": "moonshot-api"},
|
||||
{"slug": "agnes", "name": "Agnes", "name_en": "Agnes", "category": "ai_agent",
|
||||
"services": "ai_agent",
|
||||
"website": None, "console_url": None, "sdk_type": None},
|
||||
{"slug": "deepseek", "name": "DeepSeek", "name_en": "DeepSeek", "category": "ai_agent",
|
||||
"services": "ai_agent",
|
||||
"website": "https://deepseek.com", "console_url": "https://platform.deepseek.com", "sdk_type": "deepseek-api"},
|
||||
# ---- Cloudflare ----
|
||||
{"slug": "cloudflare", "name": "Cloudflare", "name_en": "Cloudflare", "category": "cloudflare",
|
||||
"services": "cloudflare,dns,ssl_cert,cdn",
|
||||
"website": "https://cloudflare.com", "console_url": "https://dash.cloudflare.com", "sdk_type": "cloudflare-api"},
|
||||
]
|
||||
|
||||
|
||||
def seed_providers(session: Session) -> int:
|
||||
"""初始化预设平台(已存在的 slug 跳过),返回新增数量"""
|
||||
"""初始化预设平台(已存在的 slug 跳过),返回新增数量
|
||||
|
||||
单次查询获取全部已存在 slug,避免逐条 SELECT 的 N 次往返。
|
||||
"""
|
||||
existing_slugs = set(session.exec(select(Provider.slug)).all())
|
||||
added = 0
|
||||
for data in PRESET_PROVIDERS:
|
||||
existing = session.exec(
|
||||
select(Provider).where(Provider.slug == data["slug"])
|
||||
).first()
|
||||
if not existing:
|
||||
if data["slug"] not in existing_slugs:
|
||||
session.add(Provider(**data))
|
||||
added += 1
|
||||
session.commit()
|
||||
if added:
|
||||
session.commit()
|
||||
return added
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
"""UTC 时间工具(替代已弃用的 datetime.utcnow)
|
||||
|
||||
Python 3.12+ 起 datetime.utcnow() 被标记为弃用,
|
||||
统一使用 datetime.now(timezone.utc) 的快捷封装。
|
||||
注意:SQLite 不保存时区信息,为兼容既有数据与比较逻辑,
|
||||
默认返回 naive UTC 时间(与 utcnow 行为一致,但来源非弃用 API)。
|
||||
"""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
def utcnow() -> datetime:
|
||||
"""返回当前 UTC 时间(naive,与 datetime.utcnow() 行为一致)"""
|
||||
return datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
|
||||
|
||||
def utcnow_iso() -> str:
|
||||
"""返回当前 UTC 时间的 ISO 格式字符串(带 Z 后缀标识 UTC)"""
|
||||
return datetime.now(timezone.utc).isoformat()
|
||||
Reference in New Issue
Block a user