Merge branch 'dev'
This commit is contained in:
@@ -4,9 +4,23 @@
|
|||||||
import logging
|
import logging
|
||||||
import asyncio
|
import asyncio
|
||||||
import sys
|
import sys
|
||||||
|
import os as _os
|
||||||
import signal
|
import signal
|
||||||
import time
|
import time
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
# 确保项目根目录在 sys.path 中 (嵌入式 CPython / PyPy 需要)
|
||||||
|
_sys_path_root = _os.path.dirname(_os.path.abspath(__file__))
|
||||||
|
if _sys_path_root not in sys.path:
|
||||||
|
sys.path.insert(0, _sys_path_root)
|
||||||
|
|
||||||
|
# Windows 控制台强制 UTF-8 (避免 GBK 编解码 emoji 报错)
|
||||||
|
try:
|
||||||
|
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||||
|
sys.stderr.reconfigure(encoding='utf-8', errors='replace')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
from services.project_engine import ProjectEngine
|
from services.project_engine import ProjectEngine
|
||||||
from services.pyenv_manager import PyEnvManager
|
from services.pyenv_manager import PyEnvManager
|
||||||
from services.proxy_service import ProxyService
|
from services.proxy_service import ProxyService
|
||||||
|
|||||||
@@ -295,12 +295,12 @@
|
|||||||
'<div class="node-url">'+esc(n.url||'')+'</div>'+
|
'<div class="node-url">'+esc(n.url||'')+'</div>'+
|
||||||
(n.notes ? '<div class="node-notes">📝 '+esc(n.notes)+'</div>' : '')+
|
(n.notes ? '<div class="node-notes">📝 '+esc(n.notes)+'</div>' : '')+
|
||||||
'<div class="node-latency" style="font-size:.7rem;color:var(--text-dim);margin-top:4px">⏱ —</div>'+
|
'<div class="node-latency" style="font-size:.7rem;color:var(--text-dim);margin-top:4px">⏱ —</div>'+
|
||||||
|
'<div class="col-info" style="font-size:.65rem;color:var(--text-dim);margin-top:2px"></div>'+
|
||||||
'</div>'+
|
'</div>'+
|
||||||
'<div class="col-right-stack">'+
|
'<div class="col-right-stack">'+
|
||||||
'<div class="mtr" id="mtr-'+id+'-cpu"><div class="mtr-data"><span class="rlabel">CPU</span> <span class="rval cpu-val">0%</span></div><canvas id="'+id+'-cpu" height="60"></canvas></div>'+
|
'<div class="mtr" id="mtr-'+id+'-cpu"><div class="mtr-data"><span class="rlabel">CPU</span> <span class="rval cpu-val">0%</span></div><canvas id="'+id+'-cpu" height="60"></canvas></div>'+
|
||||||
'<div class="mtr" id="mtr-'+id+'-mem"><div class="mtr-data"><span class="rlabel">MEM</span> <span class="rval mem-val">0%</span> <span class="mem-row-detail" style="font-size:.65rem;color:var(--text-dim)"></span></div><canvas id="'+id+'-mem" height="60"></canvas></div>'+
|
'<div class="mtr" id="mtr-'+id+'-mem"><div class="mtr-data"><span class="rlabel">MEM</span> <span class="rval mem-val">0%</span> <span class="mem-row-detail" style="font-size:.65rem;color:var(--text-dim)"></span></div><canvas id="'+id+'-mem" height="60"></canvas></div>'+
|
||||||
'<div class="mtr" id="mtr-'+id+'-net"><div class="mtr-data"><span class="rlabel">NET</span> <span class="rval net-down" style="font-size:.85rem">0</span> <span class="rval net-up" style="font-size:.85rem">0</span></div><canvas id="'+id+'-net" height="60"></canvas></div>'+
|
'<div class="mtr" id="mtr-'+id+'-net"><div class="mtr-data"><span class="rlabel">NET</span> <span class="rval net-down" style="font-size:.85rem">0</span> <span class="rval net-up" style="font-size:.85rem">0</span></div><canvas id="'+id+'-net" height="60"></canvas></div>'+
|
||||||
'<div class="col-info" style="text-align:right;font-size:.7rem;color:var(--text-dim);margin-top:4px"></div>'+
|
|
||||||
'</div>'+
|
'</div>'+
|
||||||
'<div class="col-disk"><div class="disk-list"></div></div>'+
|
'<div class="col-disk"><div class="disk-list"></div></div>'+
|
||||||
'<div class="col-extra">'+
|
'<div class="col-extra">'+
|
||||||
|
|||||||
@@ -89,7 +89,8 @@ class LogService:
|
|||||||
runtime_handler = logging.handlers.RotatingFileHandler(
|
runtime_handler = logging.handlers.RotatingFileHandler(
|
||||||
self.log_dir / "runtime" / runtime_log_file,
|
self.log_dir / "runtime" / runtime_log_file,
|
||||||
maxBytes=self._parse_size(self.config['logging'].get('max_file_size', '10MB')),
|
maxBytes=self._parse_size(self.config['logging'].get('max_file_size', '10MB')),
|
||||||
backupCount=self.config['logging'].get('max_log_files', 3)
|
backupCount=self.config['logging'].get('max_log_files', 3),
|
||||||
|
encoding='utf-8'
|
||||||
)
|
)
|
||||||
runtime_handler.setLevel(getattr(logging, self.config['logging']['level'], logging.INFO))
|
runtime_handler.setLevel(getattr(logging, self.config['logging']['level'], logging.INFO))
|
||||||
runtime_handler.setFormatter(file_formatter)
|
runtime_handler.setFormatter(file_formatter)
|
||||||
@@ -101,7 +102,8 @@ class LogService:
|
|||||||
debug_handler = logging.handlers.RotatingFileHandler(
|
debug_handler = logging.handlers.RotatingFileHandler(
|
||||||
self.log_dir / "debug" / debug_log_file,
|
self.log_dir / "debug" / debug_log_file,
|
||||||
maxBytes=self._parse_size(self.config['logging'].get('max_file_size', '10MB')),
|
maxBytes=self._parse_size(self.config['logging'].get('max_file_size', '10MB')),
|
||||||
backupCount=self.config['logging'].get('max_log_files', 3)
|
backupCount=self.config['logging'].get('max_log_files', 3),
|
||||||
|
encoding='utf-8'
|
||||||
)
|
)
|
||||||
debug_handler.setLevel(logging.DEBUG)
|
debug_handler.setLevel(logging.DEBUG)
|
||||||
debug_handler.setFormatter(file_formatter)
|
debug_handler.setFormatter(file_formatter)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""SenSu PyEnvManager — Python 版本管理 + venv + 依赖安装"""
|
"""SenSu PyEnvManager — Python 版本管理 + venv + 依赖安装"""
|
||||||
import os, sys, subprocess, logging, venv, shutil
|
import os, sys, subprocess, logging, shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
|
|
||||||
@@ -76,7 +76,8 @@ class PyEnvManager:
|
|||||||
logger.info(f"创建 venv: {venv_path} (Python {python_version or 'default'})")
|
logger.info(f"创建 venv: {venv_path} (Python {python_version or 'default'})")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
venv.create(str(venv_path), with_pip=True, clear=True)
|
import venv as _venv
|
||||||
|
_venv.create(str(venv_path), with_pip=True, clear=True)
|
||||||
# Install/upgrade pip
|
# Install/upgrade pip
|
||||||
pip = str(venv_path / "bin" / "pip")
|
pip = str(venv_path / "bin" / "pip")
|
||||||
subprocess.run([pip, "install", "--upgrade", "pip"], capture_output=True, timeout=60)
|
subprocess.run([pip, "install", "--upgrade", "pip"], capture_output=True, timeout=60)
|
||||||
|
|||||||
@@ -71,9 +71,13 @@ if exist "config\framework\base_config.yaml" (
|
|||||||
echo.
|
echo.
|
||||||
if %FAIL% gtr 0 (
|
if %FAIL% gtr 0 (
|
||||||
echo [WARN] %FAIL% 项缺失,自动安装...
|
echo [WARN] %FAIL% 项缺失,自动安装...
|
||||||
"%PYTHON%" -m pip install -r requirements.txt
|
"%PYTHON%" -m pip install -r requirements.txt --no-warn-script-location --root-user-action=ignore 2>&1
|
||||||
if %errorlevel% neq 0 (
|
if %errorlevel% neq 0 (
|
||||||
echo [FAIL] 安装失败,请手动执行: .venv\Scripts\pip install -r requirements.txt
|
if %NO_VENV% equ 1 (
|
||||||
|
echo [FAIL] 安装失败,请手动执行: pip install -r requirements.txt
|
||||||
|
) else (
|
||||||
|
echo [FAIL] 安装失败,请手动执行: .venv\Scripts\pip install -r requirements.txt
|
||||||
|
)
|
||||||
pause
|
pause
|
||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
@@ -86,6 +90,9 @@ echo 🚀 启动 SenSu (无头模式)...
|
|||||||
echo Web 面板: http://0.0.0.0:4200/SenSu
|
echo Web 面板: http://0.0.0.0:4200/SenSu
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
|
:: 确保项目根目录在 Python 搜索路径中 (嵌入式 CPython 需要)
|
||||||
|
set PYTHONPATH=%~dp0;%PYTHONPATH%
|
||||||
|
|
||||||
"%PYTHON%" main.py --headless
|
"%PYTHON%" main.py --headless
|
||||||
|
|
||||||
pause
|
pause
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ window.DashboardModule = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var base = window.location.pathname.split("/").slice(0, 2).join("/");
|
var base = window.location.pathname.split("/").slice(0, 2).join("/");
|
||||||
var ws = new WebSocket("ws://" + location.host + base + "/api/system/ws");
|
var proto = location.protocol === 'https:' ? 'wss://' : 'ws://';
|
||||||
|
var ws = new WebSocket(proto + location.host + base + "/api/system/ws");
|
||||||
self.ws = ws;
|
self.ws = ws;
|
||||||
|
|
||||||
ws.onopen = function() {
|
ws.onopen = function() {
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ window.LogsModule = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var base = window.location.pathname.split("/").slice(0, 2).join("/");
|
var base = window.location.pathname.split("/").slice(0, 2).join("/");
|
||||||
var ws = new WebSocket("ws://" + location.host + base + "/api/logs/ws");
|
var proto = location.protocol === 'https:' ? 'wss://' : 'ws://';
|
||||||
|
var ws = new WebSocket(proto + location.host + base + "/api/logs/ws");
|
||||||
self.ws = ws;
|
self.ws = ws;
|
||||||
|
|
||||||
ws.onopen = function() {
|
ws.onopen = function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user