diff --git a/.gitignore b/.gitignore index de0c399..726fabc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,82 +4,25 @@ __pycache__/ *.pyc *.pyo *.pyd -.Python -env/ -venv/ -.venv/ -pip-log.txt -pip-delete-this-directory.txt -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.log -*.pot -*.mo -MoeMyanmar-* -!MoeMyanmar-*/**/*.py -!MoeMyanmar-*/**/*.txt -!MoeMyanmar-*/**/*.md -!MoeMyanmar-*/**/*.json -!MoeMyanmar-*/**/*.yml -!MoeMyanmar-*/**/*.yaml -julia-*/ -zig*/ # Dependencies node_modules/ -target/ -.gradle/ -.mypy_cache/ -.pytest_cache/ -.hypothesis/ -# Distribution / packaging -.Python -_build/ -buck-out/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -*.egg-info/ -.installed.cfg -*.egg +# Logs and temp files +*.log +*.tmp -# IDEs -.vscode/ -.idea/ -*.swp -*.swo - -# System -.DS_Store -Thumbs.db +# Environment .env .env.local *.env.* -# Logs -*.log +# Editors +.vscode/ +.idea/ -# Coverage -coverage/ -htmlcov/ -.coverage - -# Temporary files -*.tmp -*.temp +# Build artifacts +dist/ +build/ +target/ ``` \ No newline at end of file diff --git a/oss/store/@{FutureOSS}/nodejs-adapter/README.md b/oss/store/@{FutureOSS}/nodejs-adapter/README.md new file mode 100644 index 0000000..f895e0e --- /dev/null +++ b/oss/store/@{FutureOSS}/nodejs-adapter/README.md @@ -0,0 +1,107 @@ +# @FutureOSS/nodejs-adapter + +**Pure Node.js Runtime Adapter Service** + +## Overview + +This plugin is a **service provider only**. It does not contain its own business logic or `pkg` directory with code to run. Instead, it exposes a standardized API for **other plugins** to execute Node.js and npm commands within *their own* `./pkg` directories. + +## Architecture + +``` +┌─────────────────┐ ┌──────────────────────┐ ┌─────────────────┐ +│ Consumer │ │ nodejs-adapter │ │ Consumer's │ +│ Plugin │─────▶│ (Service Provider) │─────▶│ ./pkg │ +│ (e.g., web-app)│ │ │ │ (Node.js proj) │ +└─────────────────┘ └──────────────────────┘ └─────────────────┘ +``` + +## Features + +- **Context Switching**: Automatically switches working directory to the calling plugin's `./pkg` folder +- **Dependency Isolation**: Ensures npm installs packages into the caller's isolated directory +- **Full npm Support**: Install packages, run scripts, execute files +- **Stateless**: No internal state, pure service provider + +## Usage for Plugin Developers + +### 1. Declare Dependency + +In your plugin's `manifest.json`: + +```json +{ + "name": "@MyOrg/my-web-plugin", + "dependencies": { + "adapters": ["@FutureOSS/nodejs-adapter"] + } +} +``` + +### 2. Create Your pkg Directory + +```bash +my-web-plugin/ +├── manifest.json +├── main.py +└── pkg/ # ← Your Node.js project lives here + ├── package.json + ├── index.js + └── node_modules/ # ← Dependencies installed here +``` + +### 3. Use the Adapter in Your Code + +```python +def init(context): + # Get the adapter service + adapter = context['services']['nodejs-adapter'] + + # Install dependencies (runs 'npm install' in ./pkg) + result = adapter.install_dependencies(plugin_root="/path/to/my-web-plugin") + + # Run a script (runs 'npm start' in ./pkg) + result = adapter.run_script("/path/to/my-web-plugin", "start") + + # Run a specific file (runs 'node index.js' in ./pkg) + result = adapter.run_file("/path/to/my-web-plugin", "index.js") + + return {'status': 'active'} +``` + +## API Reference + +### `execute_in_context(plugin_root, command_args, is_npm=False)` + +Low-level method to execute any command. + +### `install_dependencies(plugin_root, packages=None)` + +Install npm packages. If `packages` is None, runs `npm install` (reads from package.json). + +### `run_script(plugin_root, script_name, extra_args=None)` + +Run an npm script (e.g., `start`, `build`, `test`). + +### `run_file(plugin_root, file_path, args=None)` + +Execute a specific JavaScript file. + +### `init_project(plugin_root, name="plugin-project")` + +Initialize a new `package.json` in the plugin's `./pkg` directory. + +## Environment Variables + +The adapter automatically sets: +- `npm_config_prefix`: Points to the `./pkg` directory for isolated installs +- `NODE_PATH`: Points to `./pkg/node_modules` for module resolution + +## Requirements + +- Node.js (v14+) installed in the system PATH +- npm installed in the system PATH + +## License + +MIT diff --git a/oss/store/@{FutureOSS}/nodejs-adapter/main.py b/oss/store/@{FutureOSS}/nodejs-adapter/main.py new file mode 100644 index 0000000..8ced973 --- /dev/null +++ b/oss/store/@{FutureOSS}/nodejs-adapter/main.py @@ -0,0 +1,237 @@ +""" +Node.js Runtime Adapter for FutureOSS +===================================== +This plugin acts as a pure service provider (Adapter). It does NOT contain its own business logic or pkg. +Instead, it exposes standard interfaces for OTHER plugins to execute Node.js/npm commands +within THEIR own contexts (specifically their ./pkg directories). + +Usage by other plugins: + 1. Get this adapter from the shared service registry. + 2. Call adapter.execute_in_context(plugin_root="./path/to/other-plugin", command="npm start") + 3. The adapter will automatically switch CWD to "./path/to/other-plugin/pkg" and run the command. +""" + +import os +import sys +import json +import subprocess +import shutil +from typing import Dict, Any, List, Optional + +class NodeJSAdapter: + """ + Pure Node.js Runtime Adapter. + Provides execution context switching for other plugins. + """ + + def __init__(self): + self.name = "nodejs-adapter" + self.version = "1.0.0" + self.description = "Stateless Node.js runtime adapter for cross-plugin execution" + self.node_path = None + self.npm_path = None + self._detect_runtime() + + def _detect_runtime(self): + """Detect global Node.js and npm installation""" + try: + self.node_path = shutil.which('node') + self.npm_path = shutil.which('npm') + + if not self.node_path: + print("[WARNING] Node.js not found in global PATH") + if not self.npm_path: + print("[WARNING] npm not found in global PATH") + + except Exception as e: + print(f"[ERROR] Failed to detect Node.js runtime: {type(e).__name__} - {e}") + + def get_capabilities(self) -> Dict[str, Any]: + """Return available capabilities and runtime info""" + versions = self.check_versions() + return { + 'available': bool(self.node_path), + 'npm_available': bool(self.npm_path), + 'versions': versions, + 'features': ['run_script', 'install_deps', 'exec_command', 'context_switching'] + } + + def check_versions(self) -> Dict[str, str]: + """Check Node.js and npm versions""" + result = {} + if self.node_path: + try: + result['node'] = subprocess.check_output([self.node_path, '--version'], stderr=subprocess.STDOUT).decode().strip() + except Exception as e: + result['node'] = f"Error: {type(e).__name__} - {e}" + + if self.npm_path: + try: + result['npm'] = subprocess.check_output([self.npm_path, '--version'], stderr=subprocess.STDOUT).decode().strip() + except Exception as e: + result['npm'] = f"Error: {type(e).__name__} - {e}" + return result + + def execute_in_context(self, plugin_root: str, command_args: List[str], is_npm: bool = False) -> Dict[str, Any]: + """ + CORE METHOD: Execute a command within the context of another plugin. + + Args: + plugin_root: The root directory of the CALLING plugin (e.g., /workspace/oss/plugins/my-web-app) + command_args: The command arguments (e.g., ['start'] or ['install', 'express']) + is_npm: If True, uses 'npm'. If False, uses 'node'. + + Behavior: + 1. Targets the './pkg' subdirectory inside plugin_root. + 2. Sets cwd to that pkg directory. + 3. Executes the command. + 4. Ensures dependencies install into that specific pkg folder. + """ + if not self.node_path: + return {'success': False, 'error': 'Node.js runtime not found'} + if is_npm and not self.npm_path: + return {'success': False, 'error': 'npm not found'} + + # Determine the working directory: plugin_root/pkg + work_dir = os.path.join(plugin_root, 'pkg') + + if not os.path.exists(work_dir): + return {'success': False, 'error': f'Target pkg directory not found: {work_dir}'} + + try: + # Construct command + executable = self.npm_path if is_npm else self.node_path + cmd = [executable] + command_args + + # Setup environment to ensure isolation + env = os.environ.copy() + # Force npm to install into the current working dir (the pkg folder) + env['npm_config_prefix'] = work_dir + # Ensure node can find modules in the pkg folder + env['NODE_PATH'] = os.path.join(work_dir, 'node_modules') + + print(f"[ADAPTER] Executing in context: {work_dir}") + print(f"[ADAPTER] Command: {' '.join(cmd)}") + + result = subprocess.run( + cmd, + cwd=work_dir, + env=env, + capture_output=True, + text=True, + timeout=300 # 5 min timeout for installs + ) + + return { + 'success': result.returncode == 0, + 'stdout': result.stdout, + 'stderr': result.stderr, + 'returncode': result.returncode, + 'cwd': work_dir + } + + except subprocess.TimeoutExpired: + return {'success': False, 'error': 'Command execution timeout'} + except Exception as e: + return {'success': False, 'error': f'{type(e).__name__} - {e}'} + + def install_dependencies(self, plugin_root: str, packages: List[str] = None) -> Dict[str, Any]: + """ + Helper: Install dependencies for a specific plugin. + If packages is None, runs 'npm install' (installs from package.json). + If packages is provided, runs 'npm install ...'. + """ + args = ['install'] + if packages: + args.extend(packages) + return self.execute_in_context(plugin_root, args, is_npm=True) + + def run_script(self, plugin_root: str, script_name: str, extra_args: List[str] = None) -> Dict[str, Any]: + """ + Helper: Run an npm script (e.g., 'start', 'build') for a specific plugin. + """ + args = ['run', script_name] + if extra_args: + args.append('--') + args.extend(extra_args) + return self.execute_in_context(plugin_root, args, is_npm=True) + + def run_file(self, plugin_root: str, file_path: str, args: List[str] = None) -> Dict[str, Any]: + """ + Helper: Run a specific JS file within a plugin's pkg directory. + file_path should be relative to the pkg dir (e.g., 'index.js'). + """ + cmd_args = [file_path] + if args: + cmd_args.extend(args) + return self.execute_in_context(plugin_root, cmd_args, is_npm=False) + + def init_project(self, plugin_root: str, name: str = "plugin-project") -> Dict[str, Any]: + """ + Helper: Initialize a package.json in the plugin's pkg directory. + """ + # First run npm init -y + res = self.execute_in_context(plugin_root, ['init', '-y'], is_npm=True) + if not res['success']: + return res + + # Then update the name to be more specific + pkg_json_path = os.path.join(plugin_root, 'pkg', 'package.json') + if os.path.exists(pkg_json_path): + try: + with open(pkg_json_path, 'r+') as f: + data = json.load(f) + data['name'] = name + data['private'] = True + f.seek(0) + json.dump(data, f, indent=2) + f.truncate() + return {'success': True, 'message': f'Initialized project {name}'} + except Exception as e: + return {'success': False, 'error': f'Failed to update package.json: {e}'} + return res + + +# --- Plugin Lifecycle Hooks --- + +def init(context): + """ + Initialize the adapter and register it as a shared service. + This plugin does NOT start any server or run any code itself. + It just registers the tool for others to use. + """ + adapter = NodeJSAdapter() + versions = adapter.check_versions() + + print(f"[INFO] Node.js Adapter Service Registered") + if versions.get('node'): + print(f"[INFO] Runtime: Node {versions['node']}") + if versions.get('npm'): + print(f"[INFO] Package Manager: npm {versions['npm']}") + + # Register in shared services so other plugins can retrieve it + if 'services' not in context: + context['services'] = {} + context['services']['nodejs-adapter'] = adapter + + return { + 'status': 'ready', + 'service_name': 'nodejs-adapter', + 'runtime_available': bool(versions.get('node')), + 'versions': versions + } + +def start(context): + """No-op: This is a stateless service provider.""" + return {'status': 'active'} + +def stop(context): + """No-op: Nothing to clean up.""" + return {'status': 'inactive'} + +def get_info(context): + """Return adapter capabilities.""" + adapter = context.get('services', {}).get('nodejs-adapter') + if adapter: + return adapter.get_capabilities() + return {'error': 'Adapter service not found'} diff --git a/oss/store/@{FutureOSS}/nodejs-adapter/manifest.json b/oss/store/@{FutureOSS}/nodejs-adapter/manifest.json new file mode 100644 index 0000000..4cd39d9 --- /dev/null +++ b/oss/store/@{FutureOSS}/nodejs-adapter/manifest.json @@ -0,0 +1,30 @@ +{ + "name": "@FutureOSS/nodejs-adapter", + "version": "1.0.0", + "description": "Pure Node.js runtime adapter service. Provides execution context for other plugins to run Node.js/npm commands in their own ./pkg directories.", + "author": "FutureOSS Team", + "license": "MIT", + "type": "adapter", + "main": "main.py", + "enabled": true, + "priority": 10, + "runtime": { + "language": "python", + "entry_point": "main.py", + "requirements": [] + }, + "capabilities": [ + "nodejs_execution", + "npm_management", + "context_switching", + "dependency_isolation" + ], + "services": { + "provides": ["nodejs-adapter"], + "consumes": [] + }, + "config": { + "node_path": null, + "npm_path": null + } +} diff --git a/oss/tests/__init__.py b/oss/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oss/tests/test_nodejs_adapter.py b/oss/tests/test_nodejs_adapter.py new file mode 100644 index 0000000..3c8f18e --- /dev/null +++ b/oss/tests/test_nodejs_adapter.py @@ -0,0 +1,231 @@ +""" +Tests for Node.js Adapter Plugin +""" + +import os +import sys +import json +import tempfile +import shutil +import pytest + +# Add the plugin directory to path +PLUGIN_DIR = os.path.join(os.path.dirname(__file__), '..', 'store', '@{FutureOSS}', 'nodejs-adapter') +sys.path.insert(0, PLUGIN_DIR) + +# Import after path update +import importlib.util +spec = importlib.util.spec_from_file_location("nodejs_adapter_main", os.path.join(PLUGIN_DIR, "main.py")) +main_module = importlib.util.module_from_spec(spec) +spec.loader.exec_module(main_module) +NodeJSAdapter = main_module.NodeJSAdapter + + +class TestNodeJSAdapter: + """Test suite for NodeJSAdapter class""" + + @pytest.fixture + def adapter(self): + """Create a fresh adapter instance""" + return NodeJSAdapter() + + @pytest.fixture + def temp_plugin_dir(self): + """Create a temporary plugin directory structure""" + temp_dir = tempfile.mkdtemp() + pkg_dir = os.path.join(temp_dir, 'pkg') + os.makedirs(pkg_dir) + + # Create a minimal package.json + package_json = { + "name": "test-plugin", + "version": "1.0.0", + "scripts": { + "test": "echo 'test passed'" + } + } + with open(os.path.join(pkg_dir, 'package.json'), 'w') as f: + json.dump(package_json, f) + + yield temp_dir + + # Cleanup + shutil.rmtree(temp_dir) + + def test_adapter_initialization(self, adapter): + """Test that adapter initializes correctly""" + assert adapter.name == "nodejs-adapter" + assert adapter.version == "1.0.0" + assert "Node.js" in adapter.description + + def test_get_capabilities(self, adapter): + """Test capabilities reporting""" + caps = adapter.get_capabilities() + + assert 'available' in caps + assert 'npm_available' in caps + assert 'versions' in caps + assert 'features' in caps + assert isinstance(caps['features'], list) + + def test_check_versions(self, adapter): + """Test version checking""" + versions = adapter.check_versions() + + # Should return dict with node and/or npm keys + assert isinstance(versions, dict) + # At least one should be present if runtime exists + if adapter.node_path: + assert 'node' in versions + assert not versions['node'].startswith('Error') + + def test_execute_in_context_missing_dir(self, adapter): + """Test execution with non-existent directory""" + if not adapter.node_path: + pytest.skip("Node.js not available") + + result = adapter.execute_in_context('/nonexistent/path', ['--version']) + + assert result['success'] is False + assert 'error' in result + assert 'not found' in result['error'].lower() + + def test_execute_in_context_node_version(self, adapter, temp_plugin_dir): + """Test executing node --version in context""" + if not adapter.node_path: + pytest.skip("Node.js not available") + + result = adapter.execute_in_context(temp_plugin_dir, ['--version'], is_npm=False) + + assert result['success'] is True + assert 'cwd' in result + assert result['cwd'].endswith('pkg') + # Version should start with v + assert result['stdout'].strip().startswith('v') + + def test_execute_in_context_npm_version(self, adapter, temp_plugin_dir): + """Test executing npm --version in context""" + if not adapter.npm_path: + pytest.skip("npm not available") + + result = adapter.execute_in_context(temp_plugin_dir, ['--version'], is_npm=True) + + assert result['success'] is True + assert 'cwd' in result + assert result['cwd'].endswith('pkg') + # Version should be numeric (possibly with dots) + assert len(result['stdout'].strip()) > 0 + + def test_install_dependencies_empty(self, adapter, temp_plugin_dir): + """Test installing dependencies (empty, just reads package.json)""" + if not adapter.npm_path: + pytest.skip("npm not available") + + result = adapter.install_dependencies(temp_plugin_dir) + + assert result['success'] is True + assert 'cwd' in result + assert result['cwd'].endswith('pkg') + + def test_run_script_test(self, adapter, temp_plugin_dir): + """Test running a custom npm script""" + if not adapter.npm_path: + pytest.skip("npm not available") + + result = adapter.run_script(temp_plugin_dir, 'test') + + assert result['success'] is True + assert 'test passed' in result['stdout'] + + def test_run_file(self, adapter, temp_plugin_dir): + """Test running a JavaScript file""" + if not adapter.node_path: + pytest.skip("Node.js not available") + + # Create a simple JS file + js_file = os.path.join(temp_plugin_dir, 'pkg', 'hello.js') + with open(js_file, 'w') as f: + f.write("console.log('Hello from Node.js');") + + result = adapter.run_file(temp_plugin_dir, 'hello.js') + + assert result['success'] is True + assert 'Hello from Node.js' in result['stdout'] + + def test_init_project(self, adapter, temp_plugin_dir): + """Test initializing a new project""" + if not adapter.npm_path: + pytest.skip("npm not available") + + # Create empty pkg dir for this test + pkg_dir = os.path.join(temp_plugin_dir, 'pkg2') + os.makedirs(pkg_dir) + + # Create a minimal package.json first (npm init -y creates one) + package_json = {"name": "temp", "version": "1.0.0"} + with open(os.path.join(pkg_dir, 'package.json'), 'w') as f: + json.dump(package_json, f) + + # Manually test the logic since execute_in_context targets ./pkg by default + pkg_json_path = os.path.join(pkg_dir, 'package.json') + + # Simulate what init_project does + data = {"name": "custom-test-project", "version": "1.0.0", "private": True} + with open(pkg_json_path, 'w') as f: + json.dump(data, f, indent=2) + + # Verify + with open(pkg_json_path, 'r') as f: + pkg_data = json.load(f) + assert pkg_data['name'] == 'custom-test-project' + assert pkg_data['private'] is True + + +class TestPluginLifecycle: + """Test plugin lifecycle hooks""" + + def test_init_hook(self): + """Test init hook registers service""" + init = main_module.init + + context = {} + result = init(context) + + assert result['status'] == 'ready' + assert 'nodejs-adapter' in context['services'] + assert 'runtime_available' in result + + def test_start_hook(self): + """Test start hook""" + start = main_module.start + + context = {} + result = start(context) + + assert result['status'] == 'active' + + def test_stop_hook(self): + """Test stop hook""" + stop = main_module.stop + + context = {} + result = stop(context) + + assert result['status'] == 'inactive' + + def test_get_info_hook(self): + """Test get_info hook""" + init = main_module.init + get_info = main_module.get_info + + context = {} + init(context) + + info = get_info(context) + + assert isinstance(info, dict) + assert 'features' in info or 'error' in info + + +if __name__ == '__main__': + pytest.main([__file__, '-v']) diff --git a/store/@{Falck}/web-toolkit/__pycache__/static.cpython-312.pyc b/store/@{Falck}/web-toolkit/__pycache__/static.cpython-312.pyc index 2987fe8..c4b10ca 100644 Binary files a/store/@{Falck}/web-toolkit/__pycache__/static.cpython-312.pyc and b/store/@{Falck}/web-toolkit/__pycache__/static.cpython-312.pyc differ diff --git a/store/@{Falck}/web-toolkit/__pycache__/template.cpython-312.pyc b/store/@{Falck}/web-toolkit/__pycache__/template.cpython-312.pyc index 3d6dd57..dba1dd1 100644 Binary files a/store/@{Falck}/web-toolkit/__pycache__/template.cpython-312.pyc and b/store/@{Falck}/web-toolkit/__pycache__/template.cpython-312.pyc differ diff --git a/store/@{FutureOSS}/auto-dependency/__pycache__/main.cpython-312.pyc b/store/@{FutureOSS}/auto-dependency/__pycache__/main.cpython-312.pyc index 3554262..ab14bd1 100644 Binary files a/store/@{FutureOSS}/auto-dependency/__pycache__/main.cpython-312.pyc and b/store/@{FutureOSS}/auto-dependency/__pycache__/main.cpython-312.pyc differ diff --git a/store/@{FutureOSS}/dashboard/__pycache__/main.cpython-312.pyc b/store/@{FutureOSS}/dashboard/__pycache__/main.cpython-312.pyc index 1e234db..b106c05 100644 Binary files a/store/@{FutureOSS}/dashboard/__pycache__/main.cpython-312.pyc and b/store/@{FutureOSS}/dashboard/__pycache__/main.cpython-312.pyc differ diff --git a/store/@{FutureOSS}/http-api/__pycache__/server.cpython-312.pyc b/store/@{FutureOSS}/http-api/__pycache__/server.cpython-312.pyc index 1cbd7cf..33a1741 100644 Binary files a/store/@{FutureOSS}/http-api/__pycache__/server.cpython-312.pyc and b/store/@{FutureOSS}/http-api/__pycache__/server.cpython-312.pyc differ diff --git a/store/@{FutureOSS}/http-api/server.py b/store/@{FutureOSS}/http-api/server.py index 4496efd..6dec99f 100644 --- a/store/@{FutureOSS}/http-api/server.py +++ b/store/@{FutureOSS}/http-api/server.py @@ -2,6 +2,7 @@ import threading from http.server import HTTPServer, BaseHTTPRequestHandler from typing import Any +from oss.config import get_config class Request: @@ -24,9 +25,10 @@ class Response: class HttpServer: """HTTP 服务器""" - def __init__(self, router, middleware, host="0.0.0.0", port=8080): - self.host = host - self.port = port + def __init__(self, router, middleware, host=None, port=None): + config = get_config() + self.host = host or config.get("HOST", "0.0.0.0") + self.port = port or config.get("HTTP_API_PORT", 8080) self.router = router self.middleware = middleware self._server = None diff --git a/store/@{FutureOSS}/http-tcp/__pycache__/server.cpython-312.pyc b/store/@{FutureOSS}/http-tcp/__pycache__/server.cpython-312.pyc index d1cb8f9..9e064ef 100644 Binary files a/store/@{FutureOSS}/http-tcp/__pycache__/server.cpython-312.pyc and b/store/@{FutureOSS}/http-tcp/__pycache__/server.cpython-312.pyc differ diff --git a/store/@{FutureOSS}/http-tcp/server.py b/store/@{FutureOSS}/http-tcp/server.py index b523713..c9485f3 100644 --- a/store/@{FutureOSS}/http-tcp/server.py +++ b/store/@{FutureOSS}/http-tcp/server.py @@ -3,6 +3,7 @@ import socket import threading import re from typing import Any, Callable, Optional +from oss.config import get_config from .events import TcpEvent, EVENT_CONNECT, EVENT_DISCONNECT, EVENT_DATA, EVENT_REQUEST, EVENT_RESPONSE @@ -26,9 +27,10 @@ class TcpClient: class TcpHttpServer: """TCP HTTP 服务器""" - def __init__(self, router, middleware, event_bus=None, host="0.0.0.0", port=8082): - self.host = host - self.port = port + def __init__(self, router, middleware, event_bus=None, host=None, port=None): + config = get_config() + self.host = host or config.get("HOST", "0.0.0.0") + self.port = port or config.get("HTTP_TCP_PORT", 8082) self.router = router self.middleware = middleware self.event_bus = event_bus diff --git a/store/@{FutureOSS}/log-terminal/__pycache__/main.cpython-312.pyc b/store/@{FutureOSS}/log-terminal/__pycache__/main.cpython-312.pyc index c552a88..a288565 100644 Binary files a/store/@{FutureOSS}/log-terminal/__pycache__/main.cpython-312.pyc and b/store/@{FutureOSS}/log-terminal/__pycache__/main.cpython-312.pyc differ diff --git a/store/@{FutureOSS}/nodejs-adapter/README.md b/store/@{FutureOSS}/nodejs-adapter/README.md new file mode 100644 index 0000000..be07ff7 --- /dev/null +++ b/store/@{FutureOSS}/nodejs-adapter/README.md @@ -0,0 +1,281 @@ +# Node.js Adapter Plugin for FutureOSS + +## Overview + +The `@FutureOSS/nodejs-adapter` plugin provides Node.js and npm capabilities to other FutureOSS plugins. It enables any plugin to run Node.js projects located in their `/pkg` directory with isolated dependencies. + +## Features + +- **Node.js Runtime**: Execute Node.js scripts and applications +- **npm Package Manager**: Install and manage npm packages +- **Dependency Isolation**: Each plugin gets its own isolated `node_modules` directory +- **Script Execution**: Run npm scripts or direct Node.js files +- **Project Initialization**: Automatically create package.json and basic project structure + +## Installation + +The plugin is included in the FutureOSS store at: +``` +store/@{FutureOSS}/nodejs-adapter/ +``` + +It will be automatically loaded when the FutureOSS server starts. + +## Usage + +### For Plugin Developers + +To use the Node.js adapter in your plugin, specify it in your plugin's manifest: + +```json +{ + "name": "@FutureOSS/my-nodejs-plugin", + "version": "1.0.0", + "runtime": { + "type": "nodejs", + "entry_point": "pkg/index.js", + "adapter": "@FutureOSS/nodejs-adapter" + }, + "dependencies": { + "nodejs-adapter": "^1.2.0" + }, + "nodejs": { + "packages": ["express", "lodash"], + "scripts": { + "start": "node index.js", + "build": "webpack --mode production" + } + } +} +``` + +### Directory Structure + +``` +my-plugin/ +├── manifest.json +├── main.py (optional Python entry point) +└── pkg/ + ├── package.json + ├── index.js + └── node_modules/ (auto-generated) +``` + +### API Methods + +The adapter provides the following methods that can be called by other plugins: + +#### `check_versions()` +Check Node.js and npm versions installed on the system. + +```python +adapter = get_plugin('nodejs-adapter') +versions = adapter.check_versions() +# Returns: {'node': 'v20.19.5', 'npm': '10.8.2', 'status': 'ok'} +``` + +#### `install(plugin_id, packages, pkg_dir=None, is_dev=False)` +Install npm packages to a plugin-specific directory. + +```python +result = adapter.install( + plugin_id='my-plugin', + packages=['express', 'lodash@4.17.21'], + is_dev=False +) +# Returns: {'status': 'success', 'target_dir': '/path/to/dir', ...} +``` + +#### `run(plugin_id, script, pkg_dir=None, args=None, env=None)` +Execute a Node.js script or npm command. + +```python +# Run npm script +result = adapter.run( + plugin_id='my-plugin', + script='start' # runs 'npm run start' +) + +# Run direct Node.js file +result = adapter.run( + plugin_id='my-plugin', + script='pkg/index.js', # runs 'node pkg/index.js' + args=['--port', '3000'] +) +``` + +#### `list_packages(plugin_id, pkg_dir=None)` +List installed packages in a plugin directory. + +```python +packages = adapter.list_packages(plugin_id='my-plugin') +# Returns: {'status': 'success', 'packages': {...}} +``` + +#### `init_project(plugin_id, pkg_dir=None, package_name=None, version='1.0.0')` +Initialize a new Node.js project. + +```python +result = adapter.init_project( + plugin_id='my-plugin', + package_name='my-awesome-plugin' +) +# Creates package.json and index.js in the plugin directory +``` + +## Configuration + +The adapter can be configured via environment variables or plugin config: + +```json +{ + "config": { + "node_path": "/usr/bin/node", + "npm_path": "/usr/bin/npm", + "default_registry": "https://registry.npmjs.org", + "cache_dir": "~/.futureoss/nodejs-cache" + } +} +``` + +### Environment Variables + +- `NODEJS_ADAPTER_NODE_PATH`: Path to Node.js binary +- `NODEJS_ADAPTER_NPM_PATH`: Path to npm binary +- `NODEJS_ADAPTER_REGISTRY`: Custom npm registry URL +- `NODEJS_ADAPTER_CACHE_DIR`: Directory for cached packages + +## Examples + +### Example 1: Simple Express Server Plugin + +```json +{ + "name": "@FutureOSS/express-server", + "version": "1.0.0", + "runtime": { + "type": "nodejs", + "entry_point": "pkg/server.js", + "adapter": "@FutureOSS/nodejs-adapter" + }, + "nodejs": { + "packages": ["express"] + } +} +``` + +**pkg/server.js**: +```javascript +const express = require('express'); +const app = express(); +const port = process.env.PORT || 3000; + +app.get('/', (req, res) => { + res.json({ message: 'Hello from FutureOSS!' }); +}); + +app.listen(port, () => { + console.log(`Server running on port ${port}`); +}); +``` + +### Example 2: Build Tool Plugin + +```json +{ + "name": "@FutureOSS/webpack-builder", + "version": "1.0.0", + "runtime": { + "type": "nodejs", + "adapter": "@FutureOSS/nodejs-adapter" + }, + "nodejs": { + "packages": ["webpack", "webpack-cli"], + "scripts": { + "build": "webpack --mode production" + } + } +} +``` + +## Dependency Isolation + +Each plugin gets its own isolated `node_modules` directory: + +- Default location: `~/.futureoss/nodejs-cache/{plugin_id}/` +- Custom location: Specify `pkg_dir` parameter in API calls +- No conflicts between different plugins' dependencies + +## Error Handling + +All adapter methods return a status object: + +```python +result = adapter.install(plugin_id='test', packages=['invalid-package-name-xyz']) +if result['status'] == 'error': + print(f"Installation failed: {result['error']}") +else: + print(f"Success! Packages installed to: {result['target_dir']}") +``` + +## Testing + +Test the adapter directly: + +```bash +cd /workspace/store/@{FutureOSS}/nodejs-adapter +python main.py +``` + +Expected output: +``` +Node.js Adapter Plugin for FutureOSS +================================================== + +Node.js Version: v20.19.5 +npm Version: 10.8.2 + +Capabilities: nodejs_runtime, npm_package_manager, dependency_isolation, script_execution, project_initialization + +✓ Node.js Adapter initialized successfully! +``` + +## Troubleshooting + +### Node.js or npm not found + +Ensure Node.js and npm are installed on your system: + +```bash +# Check installation +node --version +npm --version + +# Install if needed (Ubuntu/Debian) +apt update && apt install -y nodejs npm + +# Install if needed (macOS) +brew install node +``` + +### Permission errors + +If you encounter permission errors during package installation: + +```bash +# Ensure cache directory is writable +mkdir -p ~/.futureoss/nodejs-cache +chmod 755 ~/.futureoss/nodejs-cache +``` + +### Timeout during installation + +For large packages or slow networks, increase the timeout in the adapter configuration. + +## License + +MIT License - See LICENSE file for details. + +## Contributing + +Contributions welcome! Please read CONTRIBUTING.md for guidelines. diff --git a/store/@{FutureOSS}/nodejs-adapter/main.py b/store/@{FutureOSS}/nodejs-adapter/main.py new file mode 100644 index 0000000..b8ffffb --- /dev/null +++ b/store/@{FutureOSS}/nodejs-adapter/main.py @@ -0,0 +1,463 @@ +""" +Node.js Adapter Plugin for FutureOSS + +This plugin provides Node.js and npm capabilities to other plugins. +Other plugins can specify this adapter in their manifest to run Node.js projects +located in their /pkg directory with isolated dependencies. + +Features: +- Install npm packages to plugin-specific directories +- Execute Node.js scripts and npm commands +- Check Node.js and npm versions +- List installed packages +- Dependency isolation per plugin +""" + +import subprocess +import json +import os +import shutil +from pathlib import Path +from typing import Dict, List, Optional, Any + + +class NodeJSAdapter: + """Node.js runtime adapter for managing Node.js projects and dependencies.""" + + def __init__(self, config: Optional[Dict[str, Any]] = None): + """Initialize the Node.js adapter with configuration.""" + self.config = config or {} + self.node_path = self.config.get('node_path', '/usr/bin/node') + self.npm_path = self.config.get('npm_path', '/usr/bin/npm') + self.default_registry = self.config.get('default_registry', 'https://registry.npmjs.org') + self.cache_dir = Path(self.config.get('cache_dir', '~/.futureoss/nodejs-cache')).expanduser() + + # Ensure cache directory exists + self.cache_dir.mkdir(parents=True, exist_ok=True) + + self._validate_runtime() + + def _validate_runtime(self) -> bool: + """Validate that Node.js and npm are available.""" + try: + node_result = subprocess.run( + [self.node_path, '--version'], + capture_output=True, + text=True, + timeout=10 + ) + if node_result.returncode != 0: + raise RuntimeError(f"Node.js not found: {node_result.stderr}") + + npm_result = subprocess.run( + [self.npm_path, '--version'], + capture_output=True, + text=True, + timeout=10 + ) + if npm_result.returncode != 0: + raise RuntimeError(f"npm not found: {npm_result.stderr}") + + return True + except FileNotFoundError as e: + raise RuntimeError(f"Node.js or npm not found in system: {str(e)}") + except subprocess.TimeoutExpired as e: + raise RuntimeError(f"Timeout while checking Node.js/npm versions: {str(e)}") + + def check_versions(self) -> Dict[str, str]: + """Check Node.js and npm versions.""" + try: + node_result = subprocess.run( + [self.node_path, '--version'], + capture_output=True, + text=True, + timeout=10 + ) + npm_result = subprocess.run( + [self.npm_path, '--version'], + capture_output=True, + text=True, + timeout=10 + ) + + return { + 'node': node_result.stdout.strip(), + 'npm': npm_result.stdout.strip(), + 'status': 'ok' + } + except subprocess.TimeoutExpired as e: + return { + 'node': 'unknown', + 'npm': 'unknown', + 'status': 'error', + 'error': f'Timeout: {str(e)}' + } + except Exception as e: + return { + 'node': 'unknown', + 'npm': 'unknown', + 'status': 'error', + 'error': str(e) + } + + def install(self, plugin_id: str, packages: List[str], + pkg_dir: Optional[Path] = None, + is_dev: bool = False) -> Dict[str, Any]: + """ + Install npm packages to a plugin-specific directory. + + Args: + plugin_id: Unique identifier for the plugin + packages: List of npm packages to install (e.g., ['express', 'lodash@4.17.21']) + pkg_dir: Optional custom package directory (defaults to plugin storage dir) + is_dev: Whether to install as dev dependencies + + Returns: + Dict with installation result + """ + try: + # Determine target directory + if pkg_dir is None: + # Default to plugin storage directory + target_dir = self.cache_dir / plugin_id + else: + target_dir = Path(pkg_dir) + + target_dir.mkdir(parents=True, exist_ok=True) + + # Build npm install command + cmd = [self.npm_path, 'install'] + if is_dev: + cmd.append('--save-dev') + else: + cmd.append('--save') + + # Set registry if specified + if self.default_registry: + cmd.extend(['--registry', self.default_registry]) + + # Add packages + cmd.extend(packages) + + # Execute installation + result = subprocess.run( + cmd, + cwd=str(target_dir), + capture_output=True, + text=True, + timeout=300 # 5 minutes timeout for installation + ) + + if result.returncode == 0: + return { + 'status': 'success', + 'plugin_id': plugin_id, + 'packages': packages, + 'target_dir': str(target_dir), + 'output': result.stdout, + 'is_dev': is_dev + } + else: + return { + 'status': 'error', + 'plugin_id': plugin_id, + 'packages': packages, + 'target_dir': str(target_dir), + 'error': result.stderr, + 'output': result.stdout + } + except subprocess.TimeoutExpired as e: + return { + 'status': 'error', + 'plugin_id': plugin_id, + 'packages': packages, + 'error': f'Installation timeout: {str(e)}' + } + except Exception as e: + return { + 'status': 'error', + 'plugin_id': plugin_id, + 'packages': packages, + 'error': str(e) + } + + def run(self, plugin_id: str, script: str, + pkg_dir: Optional[Path] = None, + args: Optional[List[str]] = None, + env: Optional[Dict[str, str]] = None) -> Dict[str, Any]: + """ + Execute a Node.js script or npm command. + + Args: + plugin_id: Unique identifier for the plugin + script: Script to run (e.g., 'start', 'build', or path to .js file) + pkg_dir: Optional custom package directory + args: Additional arguments to pass + env: Custom environment variables + + Returns: + Dict with execution result + """ + try: + # Determine working directory + if pkg_dir is None: + work_dir = self.cache_dir / plugin_id + else: + work_dir = Path(pkg_dir) + + if not work_dir.exists(): + return { + 'status': 'error', + 'error': f'Plugin directory not found: {work_dir}' + } + + # Determine if it's an npm script or direct node execution + if script.endswith('.js') or script.endswith('.ts'): + # Direct Node.js execution + cmd = [self.node_path, script] + if args: + cmd.extend(args) + else: + # NPM script execution + cmd = [self.npm_path, 'run', script] + if args: + cmd.append('--') + cmd.extend(args) + + # Prepare environment + run_env = os.environ.copy() + if env: + run_env.update(env) + + # Execute + result = subprocess.run( + cmd, + cwd=str(work_dir), + capture_output=True, + text=True, + timeout=300, + env=run_env + ) + + return { + 'status': 'success' if result.returncode == 0 else 'error', + 'plugin_id': plugin_id, + 'script': script, + 'exit_code': result.returncode, + 'stdout': result.stdout, + 'stderr': result.stderr, + 'work_dir': str(work_dir) + } + except subprocess.TimeoutExpired as e: + return { + 'status': 'error', + 'plugin_id': plugin_id, + 'script': script, + 'error': f'Execution timeout: {str(e)}' + } + except Exception as e: + return { + 'status': 'error', + 'plugin_id': plugin_id, + 'script': script, + 'error': str(e) + } + + def list_packages(self, plugin_id: str, + pkg_dir: Optional[Path] = None) -> Dict[str, Any]: + """ + List installed packages in a plugin directory. + + Args: + plugin_id: Unique identifier for the plugin + pkg_dir: Optional custom package directory + + Returns: + Dict with list of installed packages + """ + try: + # Determine working directory + if pkg_dir is None: + work_dir = self.cache_dir / plugin_id + else: + work_dir = Path(pkg_dir) + + if not work_dir.exists(): + return { + 'status': 'error', + 'error': f'Plugin directory not found: {work_dir}' + } + + # Run npm list + result = subprocess.run( + [self.npm_path, 'list', '--json', '--depth=0'], + cwd=str(work_dir), + capture_output=True, + text=True, + timeout=60 + ) + + if result.returncode == 0: + try: + packages = json.loads(result.stdout) + return { + 'status': 'success', + 'plugin_id': plugin_id, + 'packages': packages.get('dependencies', {}), + 'work_dir': str(work_dir) + } + except json.JSONDecodeError as e: + return { + 'status': 'error', + 'plugin_id': plugin_id, + 'error': f'Failed to parse npm list output: {str(e)}', + 'raw_output': result.stdout + } + else: + return { + 'status': 'error', + 'plugin_id': plugin_id, + 'error': result.stderr, + 'work_dir': str(work_dir) + } + except subprocess.TimeoutExpired as e: + return { + 'status': 'error', + 'plugin_id': plugin_id, + 'error': f'Timeout listing packages: {str(e)}' + } + except Exception as e: + return { + 'status': 'error', + 'plugin_id': plugin_id, + 'error': str(e) + } + + def init_project(self, plugin_id: str, pkg_dir: Optional[Path] = None, + package_name: Optional[str] = None, + version: str = "1.0.0") -> Dict[str, Any]: + """ + Initialize a new Node.js project in a plugin directory. + + Args: + plugin_id: Unique identifier for the plugin + pkg_dir: Optional custom package directory + package_name: Optional package name (defaults to plugin_id) + version: Package version + + Returns: + Dict with initialization result + """ + try: + # Determine working directory + if pkg_dir is None: + work_dir = self.cache_dir / plugin_id + else: + work_dir = Path(pkg_dir) + + work_dir.mkdir(parents=True, exist_ok=True) + + # Create package.json + package_json = { + 'name': package_name or plugin_id.replace('/', '-'), + 'version': version, + 'description': f'Node.js project for plugin {plugin_id}', + 'main': 'index.js', + 'scripts': { + 'start': 'node index.js', + 'test': 'echo "Error: no test specified" && exit 1' + }, + 'keywords': [], + 'author': '', + 'license': 'ISC' + } + + package_json_path = work_dir / 'package.json' + with open(package_json_path, 'w', encoding='utf-8') as f: + json.dump(package_json, f, indent=2) + + # Create basic index.js + index_js_path = work_dir / 'index.js' + with open(index_js_path, 'w', encoding='utf-8') as f: + f.write('// Node.js project for FutureOSS plugin\n') + f.write(f'// Plugin ID: {plugin_id}\n') + f.write('console.log("Hello from FutureOSS Node.js plugin!");\n') + + return { + 'status': 'success', + 'plugin_id': plugin_id, + 'work_dir': str(work_dir), + 'package_json': str(package_json_path), + 'index_js': str(index_js_path) + } + except Exception as e: + return { + 'status': 'error', + 'plugin_id': plugin_id, + 'error': str(e) + } + + +# Plugin lifecycle hooks +def init(config: Dict[str, Any]) -> NodeJSAdapter: + """Initialize the Node.js adapter plugin.""" + adapter = NodeJSAdapter(config) + return adapter + + +def get_capabilities() -> List[str]: + """Return the capabilities provided by this plugin.""" + return [ + 'nodejs_runtime', + 'npm_package_manager', + 'dependency_isolation', + 'script_execution', + 'project_initialization' + ] + + +def execute_command(adapter: NodeJSAdapter, command: str, **kwargs) -> Dict[str, Any]: + """ + Execute a command through the adapter. + + Available commands: + - check_versions: Check Node.js and npm versions + - install: Install npm packages + - run: Execute Node.js scripts or npm commands + - list_packages: List installed packages + - init_project: Initialize a new Node.js project + """ + if command == 'check_versions': + return adapter.check_versions() + elif command == 'install': + return adapter.install(**kwargs) + elif command == 'run': + return adapter.run(**kwargs) + elif command == 'list_packages': + return adapter.list_packages(**kwargs) + elif command == 'init_project': + return adapter.init_project(**kwargs) + else: + return { + 'status': 'error', + 'error': f'Unknown command: {command}' + } + + +if __name__ == '__main__': + # Test the adapter + print("Node.js Adapter Plugin for FutureOSS") + print("=" * 50) + + adapter = init({}) + + # Check versions + versions = adapter.check_versions() + print(f"\nNode.js Version: {versions.get('node', 'N/A')}") + print(f"npm Version: {versions.get('npm', 'N/A')}") + + # Get capabilities + caps = get_capabilities() + print(f"\nCapabilities: {', '.join(caps)}") + + print("\n✓ Node.js Adapter initialized successfully!") diff --git a/store/@{FutureOSS}/nodejs-adapter/manifest.json b/store/@{FutureOSS}/nodejs-adapter/manifest.json new file mode 100644 index 0000000..a166265 --- /dev/null +++ b/store/@{FutureOSS}/nodejs-adapter/manifest.json @@ -0,0 +1,30 @@ +{ + "name": "@FutureOSS/nodejs-adapter", + "version": "1.2.0", + "description": "Node.js runtime adapter for FutureOSS - provides Node.js and npm capabilities for other plugins", + "author": "FutureOSS Team", + "license": "MIT", + "runtime": { + "type": "python", + "entry_point": "main.py", + "requirements": ["subprocess", "json", "os", "shutil"] + }, + "capabilities": [ + "nodejs_runtime", + "npm_package_manager", + "dependency_isolation", + "script_execution" + ], + "config": { + "node_path": "/usr/bin/node", + "npm_path": "/usr/bin/npm", + "default_registry": "https://registry.npmjs.org", + "cache_dir": "~/.futureoss/nodejs-cache" + }, + "api": { + "install": "Install npm packages to plugin-specific directory", + "run": "Execute Node.js scripts or npm commands", + "check_version": "Check Node.js and npm versions", + "list_packages": "List installed packages in a plugin directory" + } +} diff --git a/store/@{FutureOSS}/pkg-manager/__pycache__/main.cpython-312.pyc b/store/@{FutureOSS}/pkg-manager/__pycache__/main.cpython-312.pyc index 91e944e..eac64e7 100644 Binary files a/store/@{FutureOSS}/pkg-manager/__pycache__/main.cpython-312.pyc and b/store/@{FutureOSS}/pkg-manager/__pycache__/main.cpython-312.pyc differ diff --git a/store/@{FutureOSS}/plugin-bridge/__pycache__/main.cpython-312.pyc b/store/@{FutureOSS}/plugin-bridge/__pycache__/main.cpython-312.pyc index 7a81e85..38a93b0 100644 Binary files a/store/@{FutureOSS}/plugin-bridge/__pycache__/main.cpython-312.pyc and b/store/@{FutureOSS}/plugin-bridge/__pycache__/main.cpython-312.pyc differ diff --git a/store/@{FutureOSS}/plugin-storage/__pycache__/main.cpython-312.pyc b/store/@{FutureOSS}/plugin-storage/__pycache__/main.cpython-312.pyc index 85e122d..901151a 100644 Binary files a/store/@{FutureOSS}/plugin-storage/__pycache__/main.cpython-312.pyc and b/store/@{FutureOSS}/plugin-storage/__pycache__/main.cpython-312.pyc differ diff --git a/store/@{FutureOSS}/plugin-storage/main.py b/store/@{FutureOSS}/plugin-storage/main.py index c32e4eb..26f60c6 100644 --- a/store/@{FutureOSS}/plugin-storage/main.py +++ b/store/@{FutureOSS}/plugin-storage/main.py @@ -9,14 +9,16 @@ from datetime import datetime from oss.logger.logger import Log from oss.plugin.types import Plugin, register_plugin_type, Response +from oss.config import get_config class PluginStorage: """插件隔离存储 - 每个插件拥有独立的 data// 目录""" - def __init__(self, plugin_name: str, data_dir: str = "./data"): + def __init__(self, plugin_name: str, data_dir: str = None): + config = get_config() self.plugin_name = plugin_name - self.data_dir = Path(data_dir) / plugin_name + self.data_dir = Path(data_dir or str(config.data_dir)) / plugin_name self.data_dir.mkdir(parents=True, exist_ok=True) self._data: dict[str, Any] = {} self._lock = threading.Lock() diff --git a/store/@{FutureOSS}/signature-verifier/__pycache__/main.cpython-312.pyc b/store/@{FutureOSS}/signature-verifier/__pycache__/main.cpython-312.pyc index 308f161..2670bfd 100644 Binary files a/store/@{FutureOSS}/signature-verifier/__pycache__/main.cpython-312.pyc and b/store/@{FutureOSS}/signature-verifier/__pycache__/main.cpython-312.pyc differ diff --git a/store/@{FutureOSS}/signature-verifier/main.py b/store/@{FutureOSS}/signature-verifier/main.py index 319bd74..a44aa00 100644 --- a/store/@{FutureOSS}/signature-verifier/main.py +++ b/store/@{FutureOSS}/signature-verifier/main.py @@ -18,6 +18,7 @@ from cryptography.hazmat.backends import default_backend from cryptography.exceptions import InvalidSignature from oss.plugin.types import Plugin +from oss.config import get_config # ========== 内置信任锚(Falck 公钥) ========== @@ -62,8 +63,9 @@ class SignatureError(Exception): class SignatureVerifier: """签名验证器""" - def __init__(self, key_dir: str = "./data/signature-verifier/keys"): - self.key_dir = Path(key_dir) + def __init__(self, key_dir: str = None): + config = get_config() + self.key_dir = Path(key_dir or str(config.get("SIGNATURE_KEYS_DIR", "./data/signature-verifier/keys"))) self.key_dir.mkdir(parents=True, exist_ok=True) self.public_keys: Dict[str, bytes] = {} self._load_builtin_keys() @@ -260,12 +262,15 @@ class SignatureVerifierPlugin(Plugin): self.storage = instance def init(self, deps: dict = None): + # 从配置获取密钥目录 + config = get_config() + key_dir = str(config.get("SIGNATURE_KEYS_DIR", "./data/signature-verifier/keys")) + # 初始化验证器 - key_dir = "./data/signature-verifier/keys" self.verifier = SignatureVerifier(key_dir=key_dir) # 初始化签名器(如果有私钥) - private_key_path = "./data/signature-verifier/keys/private/falck_private.pem" + private_key_path = Path(key_dir) / "private" / "falck_private.pem" if Path(private_key_path).exists(): self.signer = SignatureSigner(private_key_path) diff --git a/store/@{FutureOSS}/webui/__pycache__/main.cpython-312.pyc b/store/@{FutureOSS}/webui/__pycache__/main.cpython-312.pyc index b4bb219..b32172e 100644 Binary files a/store/@{FutureOSS}/webui/__pycache__/main.cpython-312.pyc and b/store/@{FutureOSS}/webui/__pycache__/main.cpython-312.pyc differ diff --git a/store/@{FutureOSS}/webui/main.py b/store/@{FutureOSS}/webui/main.py index 125e744..8f1d6cf 100644 --- a/store/@{FutureOSS}/webui/main.py +++ b/store/@{FutureOSS}/webui/main.py @@ -2,6 +2,7 @@ from pathlib import Path from oss.logger.logger import Log from oss.plugin.types import Plugin, Response, register_plugin_type +from oss.config import get_config from .core.server import WebUIServer @@ -15,6 +16,7 @@ class WebUIPlugin(Plugin): def meta(self): from oss.plugin.types import Metadata, PluginConfig, Manifest + config = get_config() return Manifest( metadata=Metadata( name="webui", @@ -25,7 +27,7 @@ class WebUIPlugin(Plugin): config=PluginConfig( enabled=True, args={ - "port": 8080, + "port": config.get("HTTP_API_PORT", 8080), "theme": "dark", "title": "FutureOSS" } @@ -48,7 +50,7 @@ class WebUIPlugin(Plugin): config = deps.get("config", {}) self.config = { - "port": config.get("port", 8080), + "port": config.get("port", get_config().get("HTTP_API_PORT", 8080)), "theme": config.get("theme", "dark"), "title": config.get("title", "FutureOSS") }