diff --git a/.gitignore b/.gitignore index d3ed4c7..00dcd4f 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ data/signature-verifier/keys/private/ # 签名文件(可选,本地开发可能不需要) # store/**/SIGNATURE +.codebuddy/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index e397be2..4096e44 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,7 +33,7 @@ COPY pyproject.toml ./pyproject.toml COPY README.md ./README.md # 创建必要目录 -RUN mkdir -p /app/data/html-render /app/data/web-toolkit /app/data/plugin-storage /app/data/DCIM /app/data/pkg /app/logs +RUN mkdir -p /app/data/html-render /app/data/web-toolkit /app/data/plugin-storage /app/data/DCIM /app/logs # 暴露端口 EXPOSE 8080 8081 8082 diff --git a/start.sh b/start.sh index 15fdce6..3decffc 100755 --- a/start.sh +++ b/start.sh @@ -303,7 +303,7 @@ ok "Python 依赖安装完成" # ═══════════════════════════════════════════════════════════ step "初始化数据目录" -DATA_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") +DATA_DIRS=("data" "data/html-render" "data/web-toolkit" "data/plugin-storage" "data/DCIM" "data/signature-verifier/keys/private" "data/signature-verifier/keys/public" "logs") DIR_COUNT=${#DATA_DIRS[@]} DIR_CURRENT=0 diff --git a/store/@{FutureOSS}/hot-reload.disabled/manifest.json b/store/@{FutureOSS}/hot-reload.disabled/manifest.json index 3856e3d..3959012 100644 --- a/store/@{FutureOSS}/hot-reload.disabled/manifest.json +++ b/store/@{FutureOSS}/hot-reload.disabled/manifest.json @@ -9,7 +9,7 @@ "config": { "enabled": true, "args": { - "watch_dirs": ["store", "./data/pkg"], + "watch_dirs": ["store"], "watch_extensions": [".py", ".json"] } }, diff --git a/store/@{FutureOSS}/pkg/README.md b/store/@{FutureOSS}/pkg/README.md deleted file mode 100644 index 4cc3963..0000000 --- a/store/@{FutureOSS}/pkg/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# pkg 包管理 - -插件的搜索、安装、卸载和更新功能。 - -## 功能 - -- 从远程仓库搜索插件 -- 下载并安装到 `./data/pkg/` 目录 -- 卸载已安装的插件 -- 更新单个或所有插件 -- 维护已安装插件列表 - -## 使用 - -```python -pm = pkg_plugin.manager - -# 搜索 -results = pm.search("keyword") - -# 安装 -pm.install("plugin-name") -pm.install("plugin-name", version="1.0.0") - -# 卸载 -pm.uninstall("plugin-name") - -# 更新 -pm.update() # 更新所有 -pm.update("plugin-name") # 更新单个 - -# 列出已安装 -installed = pm.list_installed() -``` - -## 安装位置 - -``` -./data/pkg/ -└── <插件名>/ - ├── main.py - └── manifest.json -``` diff --git a/store/@{FutureOSS}/pkg/SIGNATURE b/store/@{FutureOSS}/pkg/SIGNATURE deleted file mode 100644 index 4afd13b..0000000 --- a/store/@{FutureOSS}/pkg/SIGNATURE +++ /dev/null @@ -1,8 +0,0 @@ -{ - "signature": "dXU/zN0Zge7OC8UZgWXZVhPn7LQyiKQw4iUVZAI0P4PA7zGed3cnXa7GFzVnUKxyZMKaOITcGeg7yIM9SWM7WRTWj3N1e6F/0ac6zQ57WgREUA2zc4w0/Vc742i0+KSrE1TkICZl1CTa1x3TG3VJQo0qw4FGPijKjJQIaA9yw+yLhm0dkMefZGVAuYRnupFvKxX1xar0vx6JPpoDmHxvU92PdzbR1ggsB5hOzIrvd3aVJ1U8GbogVhtaabToK9IXbX6qrTY32ffZpEOI5n0IqAvxZ81IUV3bwhf72nP6sedEEKJzgOGfqHhMalOpjsEHNiHnX3UgBfiXzeDn2zN0NevTGCGzvgQHc3/5o/Ct9wG8ujqlNLi37jXt1DrTnIF1IBsW73ltdaMvl4IgQ0Sln2Y7QMNt3CDtwNBSBiLUhTnMjPN7QVaCl7lMM0PJH5tWg3rlSdf7+LGUN535uMwrtEJEmhafo2lcApInEZryEmRcUb22Wl3xCqGgK5yk30QqGHCwY/h4fNhx2VE7LWIoD/jMJNH+TPXTzPPUGHOGB5zaR8v+qtohOwRYPewUkbEArg7qjsOgHerHziLYBY2yH1/4oi9/N7DYsgmRyHrl4siuo+5HtPar+q29yDORs5UgxK3VNHncElVWXQ9DGzIrm3Ffj610nw7kOiU58HrBjj8=", - "signer": "FutureOSS", - "algorithm": "RSA-SHA256", - "timestamp": 1775964952.754572, - "plugin_hash": "36a948e470e6cd7ac1b51a385f21fc615c36049e9cb3fac25cdaef8161063ef1", - "author": "FutureOSS" -} \ No newline at end of file diff --git a/store/@{FutureOSS}/pkg/__pycache__/main.cpython-313.pyc b/store/@{FutureOSS}/pkg/__pycache__/main.cpython-313.pyc deleted file mode 100644 index 5db320e..0000000 Binary files a/store/@{FutureOSS}/pkg/__pycache__/main.cpython-313.pyc and /dev/null differ diff --git a/store/@{FutureOSS}/pkg/main.py b/store/@{FutureOSS}/pkg/main.py deleted file mode 100644 index 905556e..0000000 --- a/store/@{FutureOSS}/pkg/main.py +++ /dev/null @@ -1,216 +0,0 @@ -"""包管理插件 - 搜索、安装、卸载、更新插件""" -import os -import json -import shutil -import urllib.request -import urllib.parse -from pathlib import Path -from typing import Any, Optional - -from oss.logger.logger import Log -from oss.plugin.types import Plugin, register_plugin_type - - -# 远程仓库地址(可配置) -# 插件存储在 future-oss 仓库的 store/ 目录下 -DEFAULT_REGISTRY = "https://gitee.com/starlight-apk/future-oss/raw/main" - -# 插件安装目录 -PKG_DIR = Path("./data/pkg") - - -class PackageInfo: - """包信息""" - def __init__(self): - self.name: str = "" - self.version: str = "" - self.author: str = "" - self.description: str = "" - self.download_url: str = "" - self.dependencies: list[str] = [] - - -class PackageManager: - """包管理器""" - - def __init__(self): - self.registry = DEFAULT_REGISTRY - self.index_cache: dict[str, PackageInfo] = {} - self.installed: dict[str, dict[str, Any]] = {} - self._load_installed() - - def _load_installed(self): - """加载已安装的包""" - if not PKG_DIR.exists(): - return - # 扫描 @{author}/plugin_name 结构 - for author_dir in PKG_DIR.iterdir(): - if author_dir.is_dir() and author_dir.name.startswith("@{"): - for plugin_dir in author_dir.iterdir(): - if plugin_dir.is_dir(): - manifest = plugin_dir / "manifest.json" - if manifest.exists(): - with open(manifest, "r", encoding="utf-8") as f: - full_name = author_dir.name + "/" + plugin_dir.name - self.installed[full_name] = json.load(f) - - def search(self, query: str = "") -> list[PackageInfo]: - """搜索可用的包""" - # 简化版本:直接返回本地缓存 - # 实际使用时可以通过 API 或配置文件维护一个插件索引 - return self._search_from_cache(query) - - def _search_from_cache(self, query: str = "") -> list[PackageInfo]: - """从本地缓存搜索包""" - results = [] - for pkg_name, pkg_info in self.index_cache.items(): - if not query or query.lower() in pkg_name.lower() or query.lower() in pkg_info.get("description", "").lower(): - results.append(pkg_info) - return results - - def install(self, name: str, version: str = "") -> bool: - """安装包,支持 @{作者名称}/插件名称 格式""" - # 解析输入格式 @{author}/plugin 或直接插件名 - author = "FutureOSS" # 默认作者 - plugin_name = name - - if name.startswith("@{") and "}/" in name: - # 解析 @{author}/plugin 格式 - end_bracket = name.index("}/") - author = name[2:end_bracket] - plugin_name = name[end_bracket + 2:] - elif name.startswith("@{") and name.endswith("}") and "/" in name: - # 兼容旧格式 @{author/plugin} - inner = name[2:-1] - parts = inner.split("/", 1) - if len(parts) == 2: - author, plugin_name = parts - - # 搜索获取下载链接 - packages = self.search(plugin_name) - pkg_info = None - for p in packages: - if p.name == plugin_name and p.author == author: - if not version or p.version == version: - pkg_info = p - break - - if not pkg_info or not pkg_info.download_url: - # 尝试从远程仓库直接构建 URL - # 插件存储在 store/@{author}/plugin_name 目录下 - pkg_info = PackageInfo() - pkg_info.name = plugin_name - pkg_info.author = author - pkg_info.version = version or "1.0.0" - pkg_info.download_url = f"{self.registry}/store/@{{{author}}}/{plugin_name}" - - # 创建安装目录 @{author}/plugin_name - install_dir = PKG_DIR / ("@{" + author + "}") / plugin_name - install_dir.mkdir(parents=True, exist_ok=True) - - try: - # 下载 manifest.json - manifest_url = f"{pkg_info.download_url}/manifest.json" - with urllib.request.urlopen(manifest_url, timeout=10) as resp: - manifest_data = json.loads(resp.read().decode("utf-8")) - with open(install_dir / "manifest.json", "w", encoding="utf-8") as f: - json.dump(manifest_data, f, ensure_ascii=False, indent=2) - - # 下载 main.py - main_url = f"{pkg_info.download_url}/main.py" - with urllib.request.urlopen(main_url, timeout=10) as resp: - main_data = resp.read().decode("utf-8") - with open(install_dir / "main.py", "w", encoding="utf-8") as f: - f.write(main_data) - - # 更新已安装列表 - full_name = "@{" + author + "}/" + plugin_name - self.installed[full_name] = manifest_data - Log.info("pkg", f"已安装: {full_name} {manifest_data.get('metadata', {}).get('version', '')}") - return True - except Exception as e: - Log.error("pkg", f"安装失败 {name}: {e}") - # 清理失败的安装 - if install_dir.exists(): - shutil.rmtree(install_dir) - return False - - def uninstall(self, name: str) -> bool: - """卸载包,支持 @{作者名称}/插件名称 格式""" - # 解析格式获取目录路径 - if name.startswith("@{") and "}/" in name: - end_bracket = name.index("}/") - author = name[2:end_bracket] - plugin_name = name[end_bracket + 2:] - install_dir = PKG_DIR / ("@{" + author + "}") / plugin_name - elif name.startswith("@{") and name.endswith("}") and "/" in name: - # 兼容旧格式 - install_dir = PKG_DIR / name - else: - install_dir = PKG_DIR / name - - if not install_dir.exists(): - Log.info("pkg", f"包未安装: {name}") - return False - - try: - shutil.rmtree(install_dir) - # 从已安装列表中移除 - for key in list(self.installed.keys()): - if key == name or key.endswith("/" + install_dir.name): - del self.installed[key] - break - Log.info("pkg", f"已卸载: {name}") - return True - except Exception as e: - Log.error("pkg", f"卸载失败 {name}: {e}") - return False - - def update(self, name: str = "") -> bool: - """更新包""" - if name: - # 更新单个包 - if name not in self.installed: - Log.info("pkg", f"包未安装: {name}") - return False - return self.install(name) - else: - # 更新所有已安装的包 - success = True - for pkg_name in list(self.installed.keys()): - if not self.install(pkg_name): - success = False - return success - - def list_installed(self) -> dict[str, Any]: - """列出已安装的包""" - return self.installed - - -class PkgPlugin(Plugin): - """包管理插件""" - - def __init__(self): - self.manager = PackageManager() - - def init(self, deps: dict = None): - """初始化""" - PKG_DIR.mkdir(parents=True, exist_ok=True) - Log.info("pkg", "包管理器已初始化") - - def start(self): - """启动""" - Log.info("pkg", f"包管理器已启动,已安装 {len(self.manager.installed)} 个包") - - def stop(self): - """停止""" - pass - - -# 注册类型 -register_plugin_type("PackageManager", PackageManager) -register_plugin_type("PackageInfo", PackageInfo) - - -def New(): - return PkgPlugin() diff --git a/store/@{FutureOSS}/pkg/manifest.json b/store/@{FutureOSS}/pkg/manifest.json deleted file mode 100644 index 1fdf373..0000000 --- a/store/@{FutureOSS}/pkg/manifest.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "metadata": { - "name": "pkg", - "version": "1.0.0", - "author": "FutureOSS", - "description": "包管理 - 插件的搜索、安装、卸载和更新", - "type": "utility" - }, - "config": { - "enabled": true, - "args": { - "registry": "https://gitee.com/starlight-apk/future-oss-pkg/raw/main", - "install_dir": "./data/pkg" - } - }, - "dependencies": [], - "permissions": [] -} diff --git a/store/@{FutureOSS}/plugin-loader-pro.disabled/core/manager.py b/store/@{FutureOSS}/plugin-loader-pro.disabled/core/manager.py index 7563d3e..c53c938 100644 --- a/store/@{FutureOSS}/plugin-loader-pro.disabled/core/manager.py +++ b/store/@{FutureOSS}/plugin-loader-pro.disabled/core/manager.py @@ -43,7 +43,6 @@ class ProPluginManager: ProLogger.info("loader", "开始扫描插件...") self._load_from_dir(Path(store_dir)) - self._load_from_dir(Path("./data/pkg")) ProLogger.info("loader", f"共加载 {len(self.plugins)} 个插件") diff --git a/store/@{FutureOSS}/plugin-loader/README.md b/store/@{FutureOSS}/plugin-loader/README.md index 652aa52..d4c368f 100644 --- a/store/@{FutureOSS}/plugin-loader/README.md +++ b/store/@{FutureOSS}/plugin-loader/README.md @@ -4,7 +4,7 @@ ## 功能 -- 自动扫描 `store/` 和 `./data/pkg/` 目录 +- 自动扫描 `store/` 目录 - 动态加载 `main.py` 并调用 `New()` 获取实例 - 解析 `manifest.json` 获取插件元数据 - 自动扫描插件能力(AST 分析) diff --git a/store/@{FutureOSS}/plugin-loader/main.py b/store/@{FutureOSS}/plugin-loader/main.py index f6b6c58..6653504 100644 --- a/store/@{FutureOSS}/plugin-loader/main.py +++ b/store/@{FutureOSS}/plugin-loader/main.py @@ -350,7 +350,7 @@ class PluginManager: return instance def load_all(self, store_dir: str = "store"): - """加载 store 和 data/pkg 下所有插件(跳过自己)""" + """加载 store 下所有插件(跳过自己)""" # 确保 plugin 命名空间包存在(必须在最开头) import types if 'plugin' not in sys.modules: @@ -411,7 +411,6 @@ class PluginManager: # 加载其他插件 self._load_plugins_from_dir(Path(store_dir)) - self._load_plugins_from_dir(Path("./data/pkg")) # 按依赖排序 if dependency_plugin: @@ -448,44 +447,11 @@ class PluginManager: if plugin_dir.is_dir() and (plugin_dir / "main.py").exists(): return True - pkg_dir = Path("./data/pkg") - if pkg_dir.exists(): - for d in pkg_dir.iterdir(): - if d.is_dir() and (d / "main.py").exists(): - return True - return False def _bootstrap_installation(self): """引导安装 FutureOSS 官方插件""" - # 加载 pkg 插件 - pkg_dir = Path("store/@{FutureOSS}/pkg") - if pkg_dir.exists() and (pkg_dir / "main.py").exists(): - try: - pkg_instance = self.load(pkg_dir, use_sandbox=False) - if pkg_instance: - pkg_mgr = pkg_instance.manager - - Log.info("plugin-loader", "正在搜索可用插件...") - results = pkg_mgr.search() - if not results: - Log.warn("plugin-loader", "未找到远程插件") - return - - Log.info("plugin-loader", f"发现 {len(results)} 个插件,开始安装...") - installed_count = 0 - for pkg_info in results: - Log.info("plugin-loader", f"安装: {pkg_info.name}") - if pkg_mgr.install(pkg_info.name): - installed_count += 1 - - if installed_count > 0: - Log.info("plugin-loader", f"已安装 {installed_count} 个插件,重新扫描加载...") - # pkg 保留,重新加载其他插件 - except Exception as e: - Log.error("plugin-loader", f"引导安装失败: {e}") - else: - Log.info("plugin-loader", "pkg 插件不存在,跳过引导安装") + Log.info("plugin-loader", "跳过引导安装(pkg 插件已移除)") def _sort_by_dependencies(self, dep_plugin): """按依赖关系排序""" diff --git a/store/@{FutureOSS}/plugin-loader/manifest.json b/store/@{FutureOSS}/plugin-loader/manifest.json index 70fff14..9027f05 100644 --- a/store/@{FutureOSS}/plugin-loader/manifest.json +++ b/store/@{FutureOSS}/plugin-loader/manifest.json @@ -9,7 +9,7 @@ "config": { "enabled": true, "args": { - "scan_dirs": ["store", "./data/pkg"], + "scan_dirs": ["store"], "sandbox_enabled": true, "permission_check": true } diff --git a/store/@{FutureOSS}/webui/main.py b/store/@{FutureOSS}/webui/main.py index 4b82818..125e744 100644 --- a/store/@{FutureOSS}/webui/main.py +++ b/store/@{FutureOSS}/webui/main.py @@ -75,7 +75,6 @@ class WebUIPlugin(Plugin): dashboard_exists = False store_dirs = [ Path("store/@{FutureOSS}/dashboard"), - Path("./data/pkg/dashboard"), ] for d in store_dirs: if d.exists() and (d / "main.py").exists():