update project configuration and add development tools

- Add Python virtual environment patterns to .gitignore
- Replace .codebuddy with .clinerules in .gitignore
- Add .pid file for process tracking
- Add comprehensive .pylintrc configuration for Python linting
- Update start.bat with English translations and simplified functions
This commit is contained in:
Falck
2026-04-19 12:00:02 +08:00
parent 282a42081b
commit e72818399c
76 changed files with 953 additions and 152 deletions

10
.gitignore vendored
View File

@@ -2,6 +2,14 @@
QWEN.md QWEN.md
data/ data/
# 虚拟环境(用户自行创建)
.venv/
venv/
env/
*.egg-info/
dist/
build/
# 日志 # 日志
logs/ logs/
*.log *.log
@@ -11,4 +19,4 @@ data/signature-verifier/keys/private/
# 签名文件(可选,本地开发可能不需要) # 签名文件(可选,本地开发可能不需要)
# store/**/SIGNATURE # store/**/SIGNATURE
.codebuddy/ .clinerules

1
.pid Normal file
View File

@@ -0,0 +1 @@
18490

287
.pylintrc Normal file
View File

@@ -0,0 +1,287 @@
[MASTER]
jobs=4
persistent=yes
rcfile=
load-plugins=
extension-pkg-whitelist=
ignore-patterns=^test_.*\.py$
ignore=CVS
output-format=colorized
reports=yes
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
score=yes
fail-under=7.0
[MESSAGES CONTROL]
disable=all
enable=
missing-docstring,
empty-docstring,
invalid-name,
too-few-public-methods,
too-many-arguments,
too-many-instance-attributes,
too-many-locals,
too-many-public-methods,
too-many-statements,
redefined-builtin,
redefined-outer-name,
unused-argument,
unused-import,
unused-variable,
unused-wildcard-import,
wrong-import-order,
wrong-import-position,
import-error,
no-name-in-module,
no-member,
no-self-use,
not-callable,
undefined-variable,
used-before-assignment,
broad-except,
bare-except,
try-except-raise,
duplicate-code,
fixme,
trailing-whitespace,
bad-whitespace,
line-too-long,
missing-final-newline,
mixed-line-endings,
bad-continuation,
trailing-newlines,
multiple-statements,
anomalous-backslash-in-string,
deprecated-module,
deprecated-method,
super-with-arguments,
raise-missing-from,
consider-using-f-string,
consider-using-with,
use-implicit-booleaness-not-comparison,
use-list-literal,
use-dict-literal,
consider-using-enumerate,
consider-iterating-dictionary,
consider-using-set-comprehension,
consider-using-generator,
consider-using-any-or-all,
consider-using-in,
consider-using-max-builtin,
consider-using-min-builtin,
consider-using-sum,
consider-merging-isinstance,
chained-comparison,
simplifiable-if-expression,
unnecessary-lambda,
unnecessary-comprehension,
unnecessary-dunder-call,
unnecessary-pass,
unnecessary-ellipsis,
useless-else-on-loop,
useless-return,
useless-object-inheritance,
useless-suppression,
wrong-spelling-in-comment,
wrong-spelling-in-docstring
[REPORTS]
output-format=text
files-output=no
reports=yes
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
score=yes
[REFACTORING]
max-nested-blocks=5
max-line-length=88
max-module-lines=1000
max-statements=50
max-args=5
max-locals=15
max-returns=6
max-branches=12
max-statements-in-a-loop=20
max-public-methods=20
max-attributes=7
max-parents=7
max-bool-expr=5
[BASIC]
good-names=i,
j,
k,
ex,
Run,
_,
__,
fd,
msg,
v,
var,
x,
y,
z,
ax,
fig,
plt,
df,
idx,
cnt,
doc,
env,
app,
req,
res,
cls,
self,
mcs,
obj,
mod,
pkgs,
pkg,
cfg,
conf,
config,
opts,
args,
kwargs,
logger,
log
bad-names=foo,
bar,
baz,
toto,
tutu,
tata
docstring-min-length=-1
[FORMAT]
max-line-length=88
ignore-long-lines=^\\s*(# )?<?https?://\\S+>?$
single-line-if-stmt=no
single-line-class-stmt=no
max-module-lines=1000
indent-string=' '
[SIMILARITIES]
min-similarity-lines=4
ignore-comments=yes
ignore-docstrings=yes
ignore-imports=no
[TYPECHECK]
ignored-modules=
ignored-classes=optparse.Values,thread._local,_thread._local
generated-members=REQUEST,acl_users,aq_parent
contextmanager-decorators=contextlib.contextmanager
missing-member-hint=yes
missing-member-hint-distance=1
missing-member-max-choices=1
missing-member-local-gt=2
ignore-on-opaque-inference=yes
ignored-checks-for-mixins=
signature-mutators=
ignore-mixin-members=yes
ignore-none=yes
ignored-parents=
ignore-erase=no
ignore-import-error=yes
ignore-missing-imports=yes
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
additional-builtins=
[VARIABLES]
additional-builtins=
init-import=no
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
callbacks=cb_,_cb
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
allow-global-unused-variables=no
[LOGGING]
logging-modules=logging
[MISCELLANEOUS]
notes=FIXME,
XXX,
TODO,
HACK,
BUG,
NOTE,
OPTIMIZE,
REVIEW,
WARNING,
DEPRECATED
max-string-length=100
[DESIGN]
max-args=5
max-locals=15
max-returns=6
max-branches=12
max-statements=50
max-parents=7
max-attributes=7
min-public-methods=2
max-public-methods=20
[IMPORTS]
deprecated-modules=
import-graph=
ext-import-graph=
int-import-graph=
known-standard-library=
known-third-party=
known-local-folder=
preferred-modules=
allow-wildcard-with-all=no
allow-any-import-level=no
allow-relative-imports=yes
allow-from-import-under-package=yes
allow-import-from-same-module=no
allow-import-from-package=yes
allow-unused-imports=no
allow-cyclic-import=no
cyclic-import-limit=10
ignore-imports=no
ignore-import-error=yes
ignore-missing-imports=yes
preferred-modules=
single-line-exceptions=no
[EXCEPTIONS]
overgeneral-exceptions=Exception,BaseException,StandardError,ArithmeticError,LookupError,EnvironmentError,EOFError,ImportError
ignore-on-exception=no
[CLASSES]
defining-attr-methods=__init__,
__new__,
setUp,
__post_init__
valid-classmethod-first-arg=cls
valid-metaclass-classmethod-first-arg=mcs
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make
bad-dunder-names=__authors__,
__version__,
__date__,
__credits__,
__status__,
__maintainer__,
__email__,
__contact__,
__copyright__,
__license__,
__uri__,
__url__,
__program__,
__description__,
__build__
[STRING]
check-str-concat-over-line-jumps=no

188
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,188 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "FutureOSS: 启动服务",
"type": "python",
"request": "launch",
"module": "oss.cli",
"args": ["serve"],
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}",
"PYTHONUNBUFFERED": "1"
},
"cwd": "${workspaceFolder}",
"python": "${command:python.interpreterPath}"
},
{
"name": "FutureOSS: 调试模式启动",
"type": "python",
"request": "launch",
"module": "oss.cli",
"args": ["serve", "--debug"],
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}",
"PYTHONUNBUFFERED": "1",
"LOG_LEVEL": "DEBUG"
},
"cwd": "${workspaceFolder}",
"python": "${command:python.interpreterPath}"
},
{
"name": "FutureOSS: 运行测试",
"type": "python",
"request": "launch",
"module": "pytest",
"args": [
"-v",
"--tb=short",
"--cov=oss",
"--cov-report=html",
"--cov-report=term"
],
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}"
},
"cwd": "${workspaceFolder}",
"python": "${command:python.interpreterPath}"
},
{
"name": "FutureOSS: 调试插件加载器",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/oss/plugin/loader.py",
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}",
"PYTHONUNBUFFERED": "1"
},
"cwd": "${workspaceFolder}",
"python": "${command:python.interpreterPath}"
},
{
"name": "FutureOSS: 调试日志终端插件",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/store/@{FutureOSS}/log-terminal/main.py",
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}",
"PYTHONUNBUFFERED": "1"
},
"cwd": "${workspaceFolder}",
"python": "${command:python.interpreterPath}"
},
{
"name": "FutureOSS: 调试WebUI",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/store/@{FutureOSS}/webui/main.py",
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}",
"PYTHONUNBUFFERED": "1"
},
"cwd": "${workspaceFolder}",
"python": "${command:python.interpreterPath}"
},
{
"name": "FutureOSS: 调试HTTP API",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/store/@{FutureOSS}/http-api/main.py",
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}",
"PYTHONUNBUFFERED": "1"
},
"cwd": "${workspaceFolder}",
"python": "${command:python.interpreterPath}"
},
{
"name": "FutureOSS: 调试WS API",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/store/@{FutureOSS}/ws-api/main.py",
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}",
"PYTHONUNBUFFERED": "1"
},
"cwd": "${workspaceFolder}",
"python": "${command:python.interpreterPath}"
},
{
"name": "FutureOSS: 调试特定文件",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}",
"PYTHONUNBUFFERED": "1"
},
"cwd": "${workspaceFolder}",
"python": "${command:python.interpreterPath}"
},
{
"name": "FutureOSS: 附加到进程",
"type": "python",
"request": "attach",
"processId": "${command:pickProcess}",
"host": "localhost",
"port": 5678,
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "."
}
],
"justMyCode": false
},
{
"name": "FutureOSS: 运行CLI命令",
"type": "python",
"request": "launch",
"module": "oss.cli",
"args": ["${input:cliCommand}"],
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}",
"PYTHONUNBUFFERED": "1"
},
"cwd": "${workspaceFolder}",
"python": "${command:python.interpreterPath}"
}
],
"inputs": [
{
"id": "cliCommand",
"type": "promptString",
"description": "输入要执行的CLI命令install, uninstall, list等",
"default": "help"
}
],
"compounds": [
{
"name": "FutureOSS: 完整调试环境",
"configurations": [
"FutureOSS: 启动服务",
"FutureOSS: 调试日志终端插件"
],
"stopAll": true
}
]
}

153
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,153 @@
{
"python.defaultInterpreterPath": "/usr/bin/python3",
"python.terminal.activateEnvironment": true,
"python.terminal.activateEnvInCurrentTerminal": true,
"python.analysis.extraPaths": [
"${workspaceFolder}",
"${workspaceFolder}/oss",
"${workspaceFolder}/store/@{FutureOSS}"
],
"python.analysis.typeCheckingMode": "basic",
"python.analysis.autoImportCompletions": true,
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.linting.pylintPath": "pylint",
"python.linting.pylintArgs": [
"--rcfile=${workspaceFolder}/.pylintrc"
],
"python.formatting.provider": "black",
"python.formatting.blackPath": "black",
"python.formatting.blackArgs": [
"--line-length=88"
],
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"python.testing.nosetestsEnabled": false,
"python.testing.pytestPath": "pytest",
"python.testing.pytestArgs": [
"-v",
"--tb=short",
"--cov=oss",
"--cov-report=html",
"--cov-report=term"
],
"python.testing.cwd": "${workspaceFolder}",
"debug.internalConsoleOptions": "neverOpen",
"debug.javascript.usePreview": true,
"debug.onTaskErrors": "showErrors",
"debug.openDebug": "openOnDebugBreak",
"debug.openExplorerOnEnd": false,
"debug.saveBeforeStart": "allEditorsInActiveGroup",
"debug.showInStatusBar": "always",
"debug.toolBarLocation": "floating",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
},
"files.exclude": {
"**/__pycache__": true,
"**/.pytest_cache": true,
"**/.coverage": true,
"**/.mypy_cache": true,
"**/.ruff_cache": true,
"**/*.pyc": true,
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"**/node_modules": true
},
"files.watcherExclude": {
"**/__pycache__/**": true,
"**/.pytest_cache/**": true,
"**/.git/**": true,
"**/node_modules/**": true,
"**/.venv/**": true
},
"search.exclude": {
"**/__pycache__": true,
"**/.pytest_cache": true,
"**/.git": true,
"**/node_modules": true,
"**/.venv": true
},
"terminal.integrated.env.linux": {
"PYTHONPATH": "${workspaceFolder}",
"PYTHONUNBUFFERED": "1"
},
"terminal.integrated.defaultProfile.linux": "bash",
"terminal.integrated.profiles.linux": {
"bash": {
"path": "bash",
"icon": "terminal-bash"
},
"zsh": {
"path": "zsh"
},
"fish": {
"path": "fish"
},
"tmux": {
"path": "tmux",
"icon": "terminal-tmux"
},
"pwsh": {
"path": "pwsh",
"icon": "terminal-powershell"
}
},
"task.problemMatchers.neverPrompt": true,
"task.autoDetect": "on",
"task.saveBeforeRun": "always",
"explorer.autoReveal": true,
"explorer.compactFolders": false,
"explorer.confirmDelete": true,
"explorer.confirmDragAndDrop": false,
"workbench.editor.enablePreview": false,
"workbench.editor.enablePreviewFromQuickOpen": false,
"workbench.startupEditor": "none",
"workbench.colorTheme": "Default Dark Modern",
"workbench.iconTheme": "vs-seti",
"breadcrumbs.enabled": true,
"editor.minimap.enabled": true,
"editor.renderWhitespace": "boundary",
"editor.rulers": [
88
],
"editor.wordWrap": "on",
"editor.suggestSelection": "first",
"editor.quickSuggestions": {
"strings": true
},
"editor.acceptSuggestionOnEnter": "smart",
"editor.suggest.showClasses": true,
"editor.suggest.showColors": true,
"editor.suggest.showConstants": true,
"editor.suggest.showConstructors": true,
"editor.suggest.showCustomcolors": true,
"editor.suggest.showDeprecated": true,
"editor.suggest.showEnumMembers": true,
"editor.suggest.showEvents": true,
"editor.suggest.showFields": true,
"editor.suggest.showFiles": true,
"editor.suggest.showFolders": true,
"editor.suggest.showFunctions": true,
"editor.suggest.showInterfaces": true,
"editor.suggest.showIssues": true,
"editor.suggest.showKeywords": true,
"editor.suggest.showMethods": true,
"editor.suggest.showModules": true,
"editor.suggest.showOperators": true,
"editor.suggest.showProperties": true,
"editor.suggest.showReferences": true,
"editor.suggest.showSnippets": true,
"editor.suggest.showStructs": true,
"editor.suggest.showTypeParameters": true,
"editor.suggest.showUnits": true,
"editor.suggest.showUsers": true,
"editor.suggest.showValues": true,
"editor.suggest.showVariables": true,
"editor.suggest.showWords": true
}

219
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,219 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "FutureOSS: 安装依赖",
"type": "shell",
"command": "pip install -r requirements.txt",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": true
},
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "FutureOSS: 启动开发服务器",
"type": "shell",
"command": "python -m oss.cli serve",
"group": "none",
"isBackground": true,
"presentation": {
"echo": true,
"reveal": "always",
"focus": true,
"panel": "dedicated",
"showReuseMessage": true,
"clear": false
},
"problemMatcher": [
{
"pattern": [
{
"regexp": ".",
"file": 1,
"location": 2,
"message": 3
}
],
"background": {
"activeOnStart": true,
"beginsPattern": ".*启动 FutureOSS 服务.*",
"endsPattern": ".*服务已启动.*"
}
}
],
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "FutureOSS: 运行测试",
"type": "shell",
"command": "pytest -v --tb=short",
"group": "test",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "dedicated",
"showReuseMessage": true,
"clear": true
},
"problemMatcher": [
{
"owner": "python",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": [
{
"regexp": "^test_(.*)\\.py::(.*) (PASSED|FAILED|ERROR)$",
"file": 1,
"location": 2,
"severity": 3
}
]
}
],
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "FutureOSS: 代码检查",
"type": "shell",
"command": "python -m pylint oss/ store/@{FutureOSS}/ --rcfile=${workspaceFolder}/.pylintrc || echo 'Pylint检查完成'",
"group": "build",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "dedicated",
"showReuseMessage": true,
"clear": true
},
"problemMatcher": [
{
"owner": "python",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": [
{
"regexp": "^(.*):(\\d+):(\\d+): (\\w+): (.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
]
}
],
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "FutureOSS: 格式化代码",
"type": "shell",
"command": "python -m black oss/ store/@{FutureOSS}/",
"group": "build",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "dedicated",
"showReuseMessage": true,
"clear": true
},
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "FutureOSS: 清理缓存文件",
"type": "shell",
"command": "find . -type f -name '*.pyc' -delete && find . -type d -name '__pycache__' -delete && find . -type f -name '.pid' -delete",
"group": "build",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "dedicated",
"showReuseMessage": true,
"clear": true
},
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "FutureOSS: 查看服务状态",
"type": "shell",
"command": "if [ -f .pid ]; then echo '服务正在运行PID: ' && cat .pid; else echo '服务未运行'; fi",
"group": "none",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new",
"showReuseMessage": true,
"clear": true
},
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "FutureOSS: 停止服务",
"type": "shell",
"command": "if [ -f .pid ]; then kill $(cat .pid) && rm -f .pid && echo '服务已停止'; else echo '服务未运行'; fi",
"group": "none",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new",
"showReuseMessage": true,
"clear": true
},
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "FutureOSS: 重启服务",
"type": "shell",
"dependsOrder": "sequence",
"dependsOn": [
"FutureOSS: 停止服务",
"FutureOSS: 启动开发服务器"
],
"group": "none",
"presentation": {
"echo": true,
"reveal": "always",
"focus": true,
"panel": "dedicated",
"showReuseMessage": true,
"clear": true
},
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}"
}
}
]
}

Binary file not shown.

230
start.bat
View File

@@ -1,56 +1,31 @@
@echo off @echo off
chcp 65001 >nul 2>&1
setlocal enabledelayedexpansion setlocal enabledelayedexpansion
:: ═══════════════════════════════════════════════════════════ :: FutureOSS Smart Startup Script - Windows
:: FutureOSS 智能启动脚本 - Windows
:: 自动检测环境 / 安装依赖 / 进度显示 / 守护重启
:: ═══════════════════════════════════════════════════════════
cd /d "%~dp0" cd /d "%~dp0"
:: ── 处理命令行参数 ── :: Handle command line parameters
if "%1"=="--help" goto :show_help if "%1"=="--help" goto :show_help
if "%1"=="-h" goto :show_help if "%1"=="-h" goto :show_help
if "%1"=="--version" goto :show_version if "%1"=="--version" goto :show_version
if "%1"=="-v" goto :show_version if "%1"=="-v" goto :show_version
:: ── 颜色代码 ──
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
set "DEL=%%a"
)
:: ── 工具函数 ──
call :colorEcho 0B "[信息] 环境检测中..."
call :colorEcho 0A "[成功] 检测完成"
call :colorEcho 0E "[警告] 某些组件缺失"
call :colorEcho 0C "[错误] 检测失败"
:: ── Logo ──
echo. echo.
call :colorEcho 0B " ███████╗ ██████╗ ██████╗ ██████╗ ██████╗ ██████╗ " echo ========================================
call :colorEcho 0B " ██╔════╝ ██╔══██╗ ██╔══██╗ ██╔══██╗ ██╔══██╗██╔════╝ " echo FutureOSS Startup Script - Windows
call :colorEcho 0B " █████╗ ██████╔╝ ██████╔╝ ██████╔╝ ██║ ██║██║ ███╗" echo ========================================
call :colorEcho 0B " ██╔══╝ ██╔══██╗ ██╔══██╗ ██╔══██╗ ██║ ██║██║ ██║"
call :colorEcho 0B " ██║ ██║ ██║ ██║ ██║ ██║ ██║ ██████╔╝╚██████╔╝"
call :colorEcho 0B " ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ "
echo.
call :colorEcho 0F " 开发者通用工具套组 · 一切皆为插件"
call :colorEcho 07 " https://gitee.com/starlight-apk/feature-oss"
echo. echo.
:: ── 检查是否已有实例在运行 ── :: Check if an instance is already running
call :check_pid call :check_pid
if %errorlevel% neq 0 ( if %errorlevel% neq 0 (
call :colorEcho 0C "[错误] 检测到已有实例在运行,请先停止" echo [ERROR] An instance is already running, please stop it first
pause pause
exit /b 1 exit /b 1
) )
:: ═══════════════════════════════════════════════════════════ :: 1. Detect Python
:: 1. 检测 Python echo [INFO] Detecting Python...
:: ═══════════════════════════════════════════════════════════
call :colorEcho 0B "[信息] 检测 Python..."
set "PYTHON_CMD=" set "PYTHON_CMD="
for %%p in (python python3 py py3) do ( for %%p in (python python3 py py3) do (
@@ -63,47 +38,43 @@ for %%p in (python python3 py py3) do (
:found_python :found_python
if "%PYTHON_CMD%"=="" ( if "%PYTHON_CMD%"=="" (
call :colorEcho 0C "[错误] 未找到 Python请先安装 Python 3.10+" echo [ERROR] Python not found, please install Python 3.10+
call :colorEcho 0E "[提示] 下载地址: https://www.python.org/downloads/" echo [TIP] Download from: https://www.python.org/downloads/
pause pause
exit /b 1 exit /b 1
) )
for /f "tokens=*" %%i in ('%PYTHON_CMD% --version 2^>^&1') do set "PY_VER=%%i" for /f "tokens=*" %%i in ('%PYTHON_CMD% --version 2^>^&1') do set "PY_VER=%%i"
call :colorEcho 0A "[成功] %PY_VER%" echo [SUCCESS] %PY_VER%
:: 显示系统信息 :: Display system info
call :colorEcho 0B "[信息] 系统信息:" echo [INFO] System Information:
echo OS: Windows echo OS: Windows
echo 工作目录: %CD% echo Working Directory: %CD%
echo 时间: %date% %time% echo Time: %date% %time%
:: ═══════════════════════════════════════════════════════════ :: 2. Virtual Environment
:: 2. 虚拟环境
:: ═══════════════════════════════════════════════════════════
echo. echo.
call :colorEcho 0B "[信息] 配置 Python 环境..." echo [INFO] Configuring Python environment...
if not exist ".venv" ( if not exist ".venv" (
call :colorEcho 0E "[信息] 创建虚拟环境..." echo [INFO] Creating virtual environment...
%PYTHON_CMD% -m venv .venv >nul 2>&1 %PYTHON_CMD% -m venv .venv >nul 2>&1
if errorlevel 1 ( if errorlevel 1 (
call :colorEcho 0C "[错误] 无法创建虚拟环境" echo [ERROR] Cannot create virtual environment
pause pause
exit /b 1 exit /b 1
) )
call :colorEcho 0A "[成功] 虚拟环境已创建" echo [SUCCESS] Virtual environment created
) else ( ) else (
call :colorEcho 0A "[成功] 虚拟环境已存在" echo [SUCCESS] Virtual environment exists
) )
call .venv\Scripts\activate.bat >nul 2>&1 call .venv\Scripts\activate.bat >nul 2>&1
:: ═══════════════════════════════════════════════════════════ :: 3. Install Dependencies
:: 3. 安装依赖
:: ═══════════════════════════════════════════════════════════
echo. echo.
call :colorEcho 0B "[信息] 安装 Python 依赖..." echo [INFO] Installing Python dependencies...
set "DEPS=click pyyaml websockets psutil cryptography" set "DEPS=click pyyaml websockets psutil cryptography"
set "TOTAL=5" set "TOTAL=5"
@@ -111,7 +82,7 @@ set "CURRENT=0"
for %%d in (%DEPS%) do ( for %%d in (%DEPS%) do (
set /a CURRENT+=1 set /a CURRENT+=1
call :printProgress !CURRENT! !TOTAL! "安装 %%d" call :printProgress !CURRENT! !TOTAL! "Installing %%d"
%PYTHON_CMD% -c "import %%d" 2>nul %PYTHON_CMD% -c "import %%d" 2>nul
if errorlevel 1 ( if errorlevel 1 (
@@ -120,40 +91,35 @@ for %%d in (%DEPS%) do (
) )
echo. echo.
echo. echo [SUCCESS] Python dependencies installed
call :colorEcho 0A "[成功] Python 依赖安装完成"
:: 安装项目依赖 :: Install project dependencies
if exist "pyproject.toml" ( if exist "pyproject.toml" (
call :colorEcho 0E "[信息] 安装项目配置依赖..." echo [INFO] Installing project configuration dependencies...
pip install -e . -q 2>nul pip install -e . -q 2>nul
) )
if exist "requirements.txt" ( if exist "requirements.txt" (
call :colorEcho 0E "[信息] 安装 requirements.txt..." echo [INFO] Installing requirements.txt...
pip install -r requirements.txt -q 2>nul pip install -r requirements.txt -q 2>nul
) )
:: ═══════════════════════════════════════════════════════════ :: 4. Check PHP
:: 4. 检查 PHP
:: ═══════════════════════════════════════════════════════════
echo. echo.
call :colorEcho 0B "[信息] 检查 PHP..." echo [INFO] Checking PHP...
where php >nul 2>&1 where php >nul 2>&1
if errorlevel 1 ( if errorlevel 1 (
call :colorEcho 0E "[警告] PHP 未安装WebUI 可能无法正常工作" echo [WARNING] PHP not installed, WebUI may not work properly
call :colorEcho 07 "[提示] 安装: choco install php 或从 https://windows.php.net/download/ 下载" echo [TIP] Install: choco install php or download from https://windows.php.net/download/
) else ( ) else (
for /f "tokens=*" %%i in ('php --version 2^>^&1 ^| findstr /r "PHP"') do set "PHP_VER=%%i" for /f "tokens=*" %%i in ('php --version 2^>^&1 ^| findstr /r "PHP"') do set "PHP_VER=%%i"
call :colorEcho 0A "[成功] !PHP_VER!" echo [SUCCESS] !PHP_VER!
) )
:: ═══════════════════════════════════════════════════════════ :: 5. Create Data Directories
:: 5. 创建数据目录
:: ═══════════════════════════════════════════════════════════
echo. echo.
call :colorEcho 0B "[信息] 初始化数据目录..." echo [INFO] Initializing data directories...
set "DIRS=data data\html-render data\web-toolkit data\plugin-storage data\DCIM data\pkg data\signature-verifier\keys\private data\signature-verifier\keys\public logs" set "DIRS=data data\html-render data\web-toolkit data\plugin-storage data\DCIM data\pkg data\signature-verifier\keys\private data\signature-verifier\keys\public logs"
@@ -161,30 +127,28 @@ for %%d in (%DIRS%) do (
if not exist "%%d" ( if not exist "%%d" (
mkdir "%%d" >nul 2>&1 mkdir "%%d" >nul 2>&1
if errorlevel 1 ( if errorlevel 1 (
call :colorEcho 0C "[错误] 无法创建目录: %%d" echo [ERROR] Cannot create directory: %%d
) )
) )
) )
call :colorEcho 0A "[成功] 数据目录已就绪" echo [SUCCESS] Data directories ready
:: ═══════════════════════════════════════════════════════════ :: 6. Start Service
:: 6. 启动服务
:: ═══════════════════════════════════════════════════════════
echo. echo.
call :colorEcho 0B "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo ========================================
call :colorEcho 0B " 启动 FutureOSS" echo Starting FutureOSS
call :colorEcho 0B "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo ========================================
echo. echo.
:: 创建 PID 文件 :: Create PID file
call :create_pid "!random!" call :create_pid "!random!"
if "%1"=="--daemon" goto :daemon_mode if "%1"=="--daemon" goto :daemon_mode
if "%1"=="-d" goto :daemon_mode if "%1"=="-d" goto :daemon_mode
:: 前台模式 :: Foreground mode
call :colorEcho 0F "运行中... 按 Ctrl+C 停止" echo Running... Press Ctrl+C to stop
echo. echo.
set "RESTART_DELAY=3" set "RESTART_DELAY=3"
@@ -196,21 +160,21 @@ set "MAX_RESTARTS=10"
set "EXIT_CODE=%errorlevel%" set "EXIT_CODE=%errorlevel%"
if %EXIT_CODE% equ 0 ( if %EXIT_CODE% equ 0 (
call :colorEcho 0A "[成功] 服务正常退出" echo [SUCCESS] Service exited normally
goto :end goto :end
) )
:: 检查是否超过最大重启次数 :: Check if max restarts exceeded
if %RESTART_COUNT% geq %MAX_RESTARTS% ( if %RESTART_COUNT% geq %MAX_RESTARTS% (
call :colorEcho 0C "[错误] 达到最大重启次数 (%MAX_RESTARTS%),停止服务" echo [ERROR] Reached maximum restart count (%MAX_RESTARTS%), stopping service
goto :end goto :end
) )
set /a RESTART_COUNT+=1 set /a RESTART_COUNT+=1
call :colorEcho 0E "[警告] 服务异常退出 (code: %EXIT_CODE%)!RESTART_DELAY!s 后重启... (!RESTART_COUNT!/%MAX_RESTARTS% 次)" echo [WARNING] Service exited abnormally (code: %EXIT_CODE%), restarting in !RESTART_DELAY!s... (!RESTART_COUNT!/%MAX_RESTARTS%)
timeout /t !RESTART_DELAY! /nobreak >nul timeout /t !RESTART_DELAY! /nobreak >nul
:: 指数退避 (最大 60 秒) :: Exponential backoff (max 60 seconds)
if !RESTART_DELAY! lss 60 ( if !RESTART_DELAY! lss 60 (
set /a RESTART_DELAY=!RESTART_DELAY! * 2 set /a RESTART_DELAY=!RESTART_DELAY! * 2
if !RESTART_DELAY! gtr 60 set "RESTART_DELAY=60" if !RESTART_DELAY! gtr 60 set "RESTART_DELAY=60"
@@ -219,10 +183,10 @@ if !RESTART_DELAY! lss 60 (
goto :loop goto :loop
:daemon_mode :daemon_mode
call :colorEcho 0E "[警告] Windows 守护模式需要额外配置" echo [WARNING] Windows daemon mode requires additional configuration
call :colorEcho 07 "[提示] 建议使用任务计划程序或 nssm 工具实现" echo [TIP] Use Task Scheduler or nssm tool instead
echo. echo.
call :colorEcho 0B "[信息] 启动后台服务..." echo [INFO] Starting background service...
start /b %PYTHON_CMD% -m oss.cli serve > logs\daemon.log 2>&1 start /b %PYTHON_CMD% -m oss.cli serve > logs\daemon.log 2>&1
goto :end goto :end
@@ -230,65 +194,41 @@ goto :end
call :cleanup call :cleanup
call .venv\Scripts\deactivate.bat >nul 2>&1 call .venv\Scripts\deactivate.bat >nul 2>&1
echo. echo.
call :colorEcho 0B "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo ========================================
call :colorEcho 0F " FutureOSS 已停止" echo FutureOSS Stopped
call :colorEcho 0B "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo ========================================
pause pause
exit /b 0 exit /b 0
:: ── 进度条函数 ── :: Progress bar function
:printProgress :printProgress
set /a "pct=%1 * 100 / %2" set /a "pct=%1 * 100 / %2"
set /a "filled=pct / 2" set /a "filled=pct / 2"
set /a "empty=50-filled" set /a "empty=50-filled"
set "bar=" set "bar="
for /l %%i in (1,1,%filled%) do set "bar=!bar!" for /l %%i in (1,1,%filled%) do set "bar=!bar!#"
for /l %%i in (1,1,%empty%) do set "bar=!bar!" for /l %%i in (1,1,%empty%) do set "bar=!bar!-"
echo [!bar!] !pct!%% - %3 echo [!bar!] !pct!%% - %3
exit /b 0 exit /b 0
:: ── 颜色输出函数 ── :: Check if command exists
:colorEcho
set "params=%1"
set "msg=%~2"
call :colorText %params% "%msg%"
exit /b 0
:colorText
<nul set /p "=%DEL%"
findstr /v /a:%1 /R "^$" "%DEL%" nul
<nul set /p "=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%"
echo %~2
exit /b 0
:: ── 检查命令是否存在 ──
:command_exists :command_exists
where %1 >nul 2>&1 where %1 >nul 2>&1
exit /b %errorlevel% exit /b %errorlevel%
:: ── 获取当前时间戳 ── :: Get current timestamp
:get_timestamp :get_timestamp
for /f "tokens=1-3 delims=/ " %%a in ('date /t') do set "T_DATE=%%c-%%a-%%b" for /f "tokens=1-3 delims=/ " %%a in ('date /t') do set "T_DATE=%%c-%%a-%%b"
for /f "tokens=1-3 delims=: " %%a in ('time /t') do set "T_TIME=%%a:%%b:%%c" for /f "tokens=1-3 delims=: " %%a in ('time /t') do set "T_TIME=%%a:%%b:%%c"
set "TIMESTAMP=%T_DATE% %T_TIME%" set "TIMESTAMP=%T_DATE% %T_TIME%"
exit /b 0 exit /b 0
:: ── 打印分隔线 ── :: Print separator
:print_separator :print_separator
echo ═══════════════════════════════════════════════════════════ echo ========================================
exit /b 0 exit /b 0
:: ── 打印带颜色的状态 ── :: Health check
:print_status
set "status_type=%~1"
set "status_msg=%~2"
if "%status_type%"=="info" call :colorEcho 0B "[信息] %status_msg%"
if "%status_type%"=="success" call :colorEcho 0A "[成功] %status_msg%"
if "%status_type%"=="warn" call :colorEcho 0E "[警告] %status_msg%"
if "%status_type%"=="error" call :colorEcho 0C "[错误] %status_msg%"
exit /b 0
:: ── 健康检查 ──
:health_check :health_check
set "check_url=%~1" set "check_url=%~1"
set "max_retries=%~2" set "max_retries=%~2"
@@ -299,33 +239,33 @@ set "retry_count=0"
set /a retry_count+=1 set /a retry_count+=1
curl -s "%check_url%" >nul 2>&1 curl -s "%check_url%" >nul 2>&1
if %errorlevel% equ 0 ( if %errorlevel% equ 0 (
call :colorEcho 0A "[健康检查] 服务已就绪" echo [HEALTH CHECK] Service is ready
exit /b 0 exit /b 0
) )
if %retry_count% geq %max_retries% ( if %retry_count% geq %max_retries% (
call :colorEcho 0C "[健康检查] 服务启动超时" echo [HEALTH CHECK] Service startup timeout
exit /b 1 exit /b 1
) )
timeout /t 1 /nobreak >nul timeout /t 1 /nobreak >nul
goto :health_loop goto :health_loop
:: ── 创建 PID 文件 ── :: Create PID file
:create_pid :create_pid
echo %~1 > .pid echo %~1 > .pid
exit /b 0 exit /b 0
:: ── 删除 PID 文件 ── :: Remove PID file
:remove_pid :remove_pid
if exist ".pid" del ".pid" if exist ".pid" del ".pid"
exit /b 0 exit /b 0
:: ── 检查 PID 文件 ── :: Check PID file
:check_pid :check_pid
if exist ".pid" ( if exist ".pid" (
set /p PID=<.pid set /p PID=<.pid
tasklist /fi "pid eq %PID%" 2>nul | find "%PID%" >nul tasklist /fi "pid eq %PID%" 2>nul | find "%PID%" >nul
if %errorlevel% equ 0 ( if %errorlevel% equ 0 (
call :colorEcho 0E "[警告] 服务已在运行 (PID: %PID%)" echo [WARNING] Service already running (PID: %PID%)
exit /b 1 exit /b 1
) else ( ) else (
call :remove_pid call :remove_pid
@@ -333,34 +273,34 @@ if exist ".pid" (
) )
exit /b 0 exit /b 0
:: ── 显示帮助信息 ── :: Show help information
:show_help :show_help
echo. echo.
call :colorEcho 0F "FutureOSS 启动脚本 - Windows 版本" echo FutureOSS Startup Script - Windows Version
echo. echo.
echo 用法: start.bat [选项] echo Usage: start.bat [options]
echo. echo.
echo 选项: echo Options:
echo --daemon, -d 以后台模式运行Windows 建议使用任务计划程序) echo --daemon, -d Run in background mode (Windows recommends Task Scheduler)
echo --help, -h 显示此帮助信息 echo --help, -h Show this help message
echo --version, -v 显示版本信息 echo --version, -v Show version information
echo. echo.
echo 示例: echo Examples:
echo start.bat 前台运行模式 echo start.bat Foreground mode
echo start.bat --daemon 后台运行模式 echo start.bat --daemon Background mode
echo. echo.
exit /b 0 exit /b 0
:: ── 显示版本信息 ── :: Show version information
:show_version :show_version
echo FutureOSS v1.0.0 echo FutureOSS v1.0.0
echo 基于 Python 的开发者通用工具套组 echo Developer toolkit based on Python
echo. echo.
exit /b 0 exit /b 0
:: ── 清理函数 ── :: Cleanup function
:cleanup :cleanup
call :colorEcho 0E "[信息] 正在清理..." echo [INFO] Cleaning up...
call :remove_pid call :remove_pid
call :colorEcho 0A "[成功] 清理完成" echo [SUCCESS] Cleanup completed
exit /b 0 exit /b 0

0
start.sh Executable file → Normal file
View File

View File

@@ -306,7 +306,8 @@ class DashboardPlugin(Plugin):
f.write(f"<?php\n{php_vars}\n?>\n{php_content}") f.write(f"<?php\n{php_vars}\n?>\n{php_content}")
result = subprocess.run( result = subprocess.run(
["php", "-f", tmp_file], ["php", "-f", tmp_file],
capture_output=True, text=True, timeout=10 capture_output=True, text=True, timeout=10,
encoding='utf-8', errors='replace'
) )
return result.stdout if result.returncode == 0 else f"<pre>{result.stderr}</pre>" return result.stdout if result.returncode == 0 else f"<pre>{result.stderr}</pre>"
finally: finally:
@@ -319,7 +320,8 @@ class DashboardPlugin(Plugin):
@staticmethod @staticmethod
def _get_php_version() -> str: def _get_php_version() -> str:
try: try:
res = subprocess.run(['php', '-r', 'echo phpversion();'], capture_output=True, text=True, timeout=5) res = subprocess.run(['php', '-r', 'echo phpversion();'], capture_output=True, text=True, timeout=5,
encoding='utf-8', errors='replace')
return res.stdout if res.returncode == 0 else 'N/A' return res.stdout if res.returncode == 0 else 'N/A'
except Exception: except Exception:
return 'N/A' return 'N/A'

View File

@@ -104,7 +104,7 @@ class HttpServer:
self.wfile.write(resp.body.encode("utf-8")) self.wfile.write(resp.body.encode("utf-8"))
else: else:
self.wfile.write(resp.body) self.wfile.write(resp.body)
except BrokenPipeError: except (BrokenPipeError, ConnectionAbortedError, ConnectionResetError):
pass # 忽略客户端断开 pass # 忽略客户端断开
def log_message(self, format, *args): def log_message(self, format, *args):

View File

@@ -589,7 +589,8 @@ class LogTerminalPlugin(Plugin):
f.write(f"<?php\n{php_vars}\n?>\n{php_content}") f.write(f"<?php\n{php_vars}\n?>\n{php_content}")
result = subprocess.run( result = subprocess.run(
["php", "-f", tmp_file], ["php", "-f", tmp_file],
capture_output=True, text=True, timeout=10 capture_output=True, text=True, timeout=10,
encoding='utf-8', errors='replace'
) )
return result.stdout if result.returncode == 0 else f"<pre>{result.stderr}</pre>" return result.stdout if result.returncode == 0 else f"<pre>{result.stderr}</pre>"
finally: finally:

View File

@@ -134,7 +134,8 @@ class PkgManagerPlugin(Plugin):
result = subprocess.run( result = subprocess.run(
["php", "-f", tmp_file], ["php", "-f", tmp_file],
capture_output=True, text=True, timeout=10, cwd=views_dir capture_output=True, text=True, timeout=10, cwd=views_dir,
encoding='utf-8', errors='replace'
) )
return result.stdout if result.returncode == 0 else f"<pre>{result.stderr}</pre>" return result.stdout if result.returncode == 0 else f"<pre>{result.stderr}</pre>"
finally: finally:

View File

@@ -99,7 +99,8 @@ class WebUIServer:
result = subprocess.run( result = subprocess.run(
["php", "-f", tmp_file], ["php", "-f", tmp_file],
capture_output=True, text=True, timeout=10, cwd=views_dir capture_output=True, text=True, timeout=10, cwd=views_dir,
encoding='utf-8', errors='replace'
) )
if result.returncode != 0: if result.returncode != 0: