Skip to content

Commit 9463317

Browse files
committed
添加安装版本统计上报
1 parent 7ab1a66 commit 9463317

5 files changed

Lines changed: 151 additions & 0 deletions

File tree

app/api/endpoints/system.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from app.helper.rule import RuleHelper
3636
from app.helper.subscribe import SubscribeHelper
3737
from app.helper.system import SystemHelper
38+
from app.helper.usage import UsageHelper
3839
from app.log import logger
3940
from app.scheduler import Scheduler
4041
from app.schemas import ConfigChangeEventData
@@ -520,6 +521,14 @@ async def get_env_setting(_: User = Depends(get_current_active_user_async)):
520521
return schemas.Response(success=True, data=info)
521522

522523

524+
@router.get("/usage/statistic", summary="查询安装版本统计报表", response_model=schemas.Response)
525+
async def usage_statistic(_: User = Depends(get_current_active_user_async)):
526+
"""
527+
查询安装版本统计报表
528+
"""
529+
return schemas.Response(success=True, data=await UsageHelper().async_get_statistic())
530+
531+
523532
@router.post("/env", summary="更新系统配置", response_model=schemas.Response)
524533
async def set_env_setting(
525534
env: dict, _: User = Depends(get_current_active_superuser_async)

app/core/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,8 @@ class ConfigModel(BaseModel):
437437
)
438438
# 插件安装数据共享
439439
PLUGIN_STATISTIC_SHARE: bool = True
440+
# 安装版本统计上报
441+
USAGE_STATISTIC_SHARE: bool = True
440442
# 是否开启插件热加载
441443
PLUGIN_AUTO_RELOAD: bool = False
442444
# 本地插件仓库目录,多个地址使用,分隔

app/helper/usage.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import platform
2+
from pathlib import Path
3+
from typing import Any, Dict
4+
5+
from app.core.config import settings
6+
from app.log import logger
7+
from app.utils.http import AsyncRequestUtils, RequestUtils
8+
from app.utils.singleton import WeakSingleton
9+
from app.utils.system import SystemUtils
10+
from version import APP_VERSION, FRONTEND_VERSION
11+
12+
13+
class UsageHelper(metaclass=WeakSingleton):
14+
"""
15+
安装版本统计上报
16+
"""
17+
18+
_usage_report = f"{settings.MP_SERVER_HOST}/usage/report"
19+
_usage_statistic = f"{settings.MP_SERVER_HOST}/usage/statistic"
20+
21+
@staticmethod
22+
def get_frontend_version() -> str:
23+
"""
24+
获取当前前端版本。
25+
"""
26+
if SystemUtils.is_frozen() and SystemUtils.is_windows():
27+
version_file = settings.CONFIG_PATH.parent / "nginx" / "html" / "version.txt"
28+
else:
29+
version_file = Path(settings.FRONTEND_PATH) / "version.txt"
30+
if version_file.exists():
31+
try:
32+
with open(version_file, "r") as file:
33+
version = str(file.read()).strip()
34+
return version or FRONTEND_VERSION
35+
except Exception as err:
36+
logger.debug(f"加载版本文件 {version_file} 出错:{str(err)}")
37+
return FRONTEND_VERSION
38+
39+
@staticmethod
40+
def build_payload() -> Dict[str, Any]:
41+
"""
42+
构建安装版本统计上报载荷。
43+
"""
44+
return {
45+
"user_uid": SystemUtils.generate_user_unique_id(),
46+
"backend_version": APP_VERSION,
47+
"frontend_version": UsageHelper.get_frontend_version(),
48+
"version_flag": settings.VERSION_FLAG,
49+
"platform": f"{platform.system()} {platform.release()}".strip(),
50+
"arch": SystemUtils.cpu_arch(),
51+
}
52+
53+
def report(self) -> bool:
54+
"""
55+
上报当前安装实例的版本统计。
56+
"""
57+
if not settings.USAGE_STATISTIC_SHARE:
58+
return False
59+
payload = self.build_payload()
60+
if not payload.get("user_uid"):
61+
return False
62+
try:
63+
res = RequestUtils(
64+
proxies=settings.PROXY,
65+
content_type="application/json",
66+
timeout=5,
67+
).post(self._usage_report, json=payload)
68+
return bool(res is not None and res.status_code == 200)
69+
except Exception as err:
70+
logger.debug(f"上报安装版本统计失败:{str(err)}")
71+
return False
72+
73+
async def async_report(self) -> bool:
74+
"""
75+
异步上报当前安装实例的版本统计。
76+
"""
77+
if not settings.USAGE_STATISTIC_SHARE:
78+
return False
79+
payload = self.build_payload()
80+
if not payload.get("user_uid"):
81+
return False
82+
try:
83+
res = await AsyncRequestUtils(
84+
proxies=settings.PROXY,
85+
content_type="application/json",
86+
timeout=5,
87+
).post(self._usage_report, json=payload)
88+
return bool(res is not None and res.status_code == 200)
89+
except Exception as err:
90+
logger.debug(f"异步上报安装版本统计失败:{str(err)}")
91+
return False
92+
93+
def get_statistic(self) -> Dict[str, Any]:
94+
"""
95+
获取安装版本统计报表。
96+
"""
97+
if not settings.USAGE_STATISTIC_SHARE:
98+
return {}
99+
try:
100+
res = RequestUtils(proxies=settings.PROXY, timeout=10).get_res(self._usage_statistic)
101+
if res is not None and res.status_code == 200:
102+
return res.json()
103+
except Exception as err:
104+
logger.debug(f"获取安装版本统计报表失败:{str(err)}")
105+
return {}
106+
107+
async def async_get_statistic(self) -> Dict[str, Any]:
108+
"""
109+
异步获取安装版本统计报表。
110+
"""
111+
if not settings.USAGE_STATISTIC_SHARE:
112+
return {}
113+
try:
114+
res = await AsyncRequestUtils(proxies=settings.PROXY, timeout=10).get_res(self._usage_statistic)
115+
if res is not None and res.status_code == 200:
116+
return res.json()
117+
except Exception as err:
118+
logger.debug(f"异步获取安装版本统计报表失败:{str(err)}")
119+
return {}

app/scheduler.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from app.helper.image import WallpaperHelper
3737
from app.helper.message import MessageHelper
3838
from app.helper.sites import SitesHelper # noqa
39+
from app.helper.usage import UsageHelper
3940
from app.log import logger
4041
from app.schemas import Notification, NotificationType, Workflow
4142
from app.schemas.types import EventType, SystemConfigKey
@@ -264,6 +265,7 @@ class Scheduler(ConfigReloadMixin, metaclass=SingletonClass):
264265
"DATA_CLEANUP_DOWNLOAD_HISTORY_DAYS",
265266
"DATA_CLEANUP_SITE_USERDATA_DAYS",
266267
"DATA_CLEANUP_TRANSFER_HISTORY_DAYS",
268+
"USAGE_STATISTIC_SHARE",
267269
}
268270

269271
def __init__(self):
@@ -401,6 +403,11 @@ def init(self):
401403
"func": self.agent_heartbeat,
402404
"running": False,
403405
},
406+
"usage_report": {
407+
"name": "安装版本统计上报",
408+
"func": UsageHelper().report,
409+
"running": False,
410+
},
404411
}
405412

406413
# 创建定时服务
@@ -644,6 +651,17 @@ def init(self):
644651
kwargs={"job_id": "agent_heartbeat"},
645652
)
646653

654+
# 安装版本统计上报
655+
if settings.USAGE_STATISTIC_SHARE:
656+
self._scheduler.add_job(
657+
self.start,
658+
"interval",
659+
id="usage_report",
660+
name="安装版本统计上报",
661+
hours=24,
662+
kwargs={"job_id": "usage_report"},
663+
)
664+
647665
# 初始化工作流服务
648666
self.init_workflow_jobs()
649667

app/startup/lifecycle.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from app.chain.system import SystemChain
77
from app.core.config import global_vars
88
from app.helper.system import SystemHelper
9+
from app.helper.usage import UsageHelper
910
from app.startup.command_initializer import init_command, stop_command, restart_command
1011
from app.startup.modules_initializer import init_modules, stop_modules
1112
from app.startup.monitor_initializer import stop_monitor, init_monitor
@@ -29,6 +30,8 @@ async def init_extra():
2930
SystemHelper().set_system_modified()
3031
# 重启完成
3132
SystemChain().restart_finish()
33+
# 上报当前安装版本
34+
await UsageHelper().async_report()
3235

3336

3437
@asynccontextmanager

0 commit comments

Comments
 (0)