初始提交 - FutureOSS v1.0 插件化运行时框架

一切皆为插件的开发者工具运行时框架

🧩 核心特性:
  - 插件热插拔 (importlib 动态加载)
  - 依赖自动解析 (拓扑排序 + 循环检测)
  - 企业级稳定 (熔断/降级/重试/隔离)
  - 事件驱动 (发布/订阅事件总线)
  - 完整配置 (YAML 配置 + 热重载)
This commit is contained in:
Falck
2026-04-06 09:57:10 +08:00
commit 76147bae94
174 changed files with 15626 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
# HTML 渲染服务
将存储在 plugin-storage 中的 HTML 页面映射到 8080 端口。
## 功能
- 从 plugin-storage 读取 HTML
- 自动注册路由到 web-toolkit
- 支持动态页面访问
- 页面管理(存储/获取/删除/列出)
## 使用
```python
html_render = plugin_mgr.get("html-render")
# 存储 HTML 页面
html_render.store_html("index", "<h1>Hello World</h1>")
html_render.store_html("about", "<h1>About</h1>")
# 获取页面
html = html_render.get_html("index")
# 列出所有页面
pages = html_render.list_pages() # ["index", "about"]
# 删除页面
html_render.delete_page("about")
```
## 访问
```
http://localhost:8080/ → index 页面
http://localhost:8080/about → about 页面
```
## 依赖
- web-toolkitWeb 服务
- plugin-storageHTML 存储

View File

@@ -0,0 +1,99 @@
"""HTML 渲染服务 - 通过 config.json 配置,统一文件入口"""
import json
from pathlib import Path
from oss.plugin.types import Plugin, register_plugin_type, Response
class HtmlRenderPlugin(Plugin):
"""HTML 渲染插件 - 渲染服务由 html-render 提供"""
def __init__(self):
self.http_api = None
self.storage = None # plugin-storage 入口
self.config = {}
self.root_dir = None # 解析后的网站根目录
def init(self, deps: dict = None):
"""初始化 - 读取 config.json 并解析网站根目录"""
self._load_config()
print(f"[html-render] 配置加载完成: root_dir={self.root_dir}")
def start(self):
"""启动 - 注册路由到 http-api共享配置给 web-toolkit"""
# 注册首页路由
if self.http_api and hasattr(self.http_api, 'router'):
self.http_api.router.get("/", self._serve_html)
print("[html-render] 已注册路由到 http-api")
else:
print("[html-render] http-api 未加载")
# 将配置共享给 web-toolkit通过 plugin-storage 的 DCIM 共享存储)
if self.storage:
shared = self.storage.get_shared()
shared.set_shared("html-render-config", {
"root_dir": str(self.root_dir),
"index_file": self.config.get("index_file", "index.html"),
"static_prefix": self.config.get("static_prefix", "/static"),
})
print("[html-render] 配置已共享到 DCIM")
def stop(self):
"""停止"""
pass
def set_http_api(self, instance):
"""设置 http-api 实例"""
self.http_api = instance
def set_plugin_storage(self, instance):
"""设置 plugin-storage 实例(唯一文件读写入口)"""
self.storage = instance
def _load_config(self):
"""读取 config.json解析根目录"""
config_path = Path("./data/html-render/config.json")
if not config_path.exists():
print("[html-render] 警告: config.json 不存在,使用默认配置")
self.config = {"root_dir": "../website", "index_file": "index.html"}
else:
with open(config_path, "r", encoding="utf-8") as f:
self.config = json.load(f)
# 解析根目录(相对于 config.json 的路径)
root_relative = self.config.get("root_dir", "../website")
self.root_dir = (config_path.parent / root_relative).resolve()
def _serve_html(self, request):
"""提供 HTML 页面 - 通过 plugin-storage 读取并注入静态资源路径"""
index_file = self.config.get("index_file", "index.html")
if self.storage:
storage = self.storage.get_storage("html-render")
if storage.file_exists(index_file):
content = storage.read_file(index_file)
if content:
# 注入静态资源路径(相对路径 → /website/ 前缀)
content = self._inject_static_paths(content)
return Response(
status=200,
headers={"Content-Type": "text/html; charset=utf-8"},
body=content
)
return Response(status=404, body="Not Found")
def _inject_static_paths(self, html: str) -> str:
"""将相对静态资源路径替换为 /website/ 前缀"""
import re
# href="css/xxx" → href="/website/css/xxx"
html = re.sub(r'(href\s*=\s*["\'])css/', r'\1/website/css/', html)
# src="js/xxx" → src="/website/js/xxx"
html = re.sub(r'(src\s*=\s*["\'])js/', r'\1/website/js/', html)
# src="logo.svg" → src="/website/logo.svg"
html = re.sub(r'(src\s*=\s*["\'])(?!https?://|/)([\w.-]+\.(svg|png|jpg|gif|ico|webp))', r'\1/website/\2', html)
return html
register_plugin_type("HtmlRenderPlugin", HtmlRenderPlugin)
def New():
return HtmlRenderPlugin()

View File

@@ -0,0 +1,17 @@
{
"metadata": {
"name": "html-render",
"version": "1.0.0",
"author": "Falck",
"description": "HTML 渲染服务 - 提供 8080 端口的 HTML 页面服务",
"type": "utility"
},
"config": {
"enabled": true,
"args": {
"html_dir": "./data/html-render"
}
},
"dependencies": ["http-api", "plugin-storage"],
"permissions": ["http-api", "plugin-storage"]
}