186 lines
8.0 KiB
HTML
186 lines
8.0 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>插件开发指南 - Future OSS 文档</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
|
<link rel="stylesheet" href="../css/main.css" />
|
|
<link rel="stylesheet" href="../css/dock.css" />
|
|
<link rel="stylesheet" href="../css/docs.css" />
|
|
</head>
|
|
<body>
|
|
<canvas id="particles"></canvas>
|
|
<div id="dock-container"></div>
|
|
|
|
<main class="page-docs">
|
|
<header class="docs-header">
|
|
<button class="docs-hamburger" id="docs-hamburger" aria-label="切换导航菜单">
|
|
<span class="docs-hamburger-line"></span>
|
|
<span class="docs-hamburger-line"></span>
|
|
<span class="docs-hamburger-line"></span>
|
|
</button>
|
|
<div class="docs-header-title">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" width="22" height="22">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/>
|
|
</svg>
|
|
<span>文档中心</span>
|
|
</div>
|
|
<div class="docs-header-breadcrumb">插件 · 开发指南</div>
|
|
<div class="docs-header-actions">
|
|
<a href="https://gitee.com/starlight-apk/feature-oss/wikis" target="_blank" class="docs-wiki-link">完整 Wiki</a>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="docs-sidebar-overlay" id="docs-overlay"></div>
|
|
|
|
<div class="docs-layout">
|
|
<aside class="docs-sidebar" id="docs-sidebar">
|
|
<div class="docs-nav-section">
|
|
<div class="docs-nav-section-title">入门</div>
|
|
<a href="index.html" class="docs-nav-item">什么是 FutureOSS<span class="nav-path">/ 项目介绍</span></a>
|
|
<a href="why-python.html" class="docs-nav-item">为什么选择 Python<span class="nav-path">/ 技术选型</span></a>
|
|
<a href="architecture.html" class="docs-nav-item">架构设计<span class="nav-path">/ 三层架构</span></a>
|
|
</div>
|
|
<div class="docs-nav-section">
|
|
<div class="docs-nav-section-title">快速开始</div>
|
|
</div>
|
|
<div class="docs-nav-section">
|
|
<div class="docs-nav-section-title">插件</div>
|
|
<a href="plugins.html" class="docs-nav-item">官方插件列表<span class="nav-path">/ 12+ 插件</span></a>
|
|
<a href="development.html" class="docs-nav-item active">插件开发指南<span class="nav-path">/ 开发基础</span></a>
|
|
</div>
|
|
</aside>
|
|
|
|
<div class="docs-content-wrapper">
|
|
<article class="docs-content">
|
|
<h1>🛠️ 插件开发指南</h1>
|
|
|
|
<h2>插件结构</h2>
|
|
<pre><code>store/@{作者}/插件名/
|
|
├── main.py # 插件入口(必须实现 Plugin 接口)
|
|
└── manifest.json # 插件元数据(名称、版本、依赖)</code></pre>
|
|
|
|
<h2>插件接口</h2>
|
|
<pre><code>from oss.plugin.types import Plugin
|
|
|
|
class MyPlugin(Plugin):
|
|
def init(self, deps: dict = None):
|
|
# 初始化逻辑
|
|
pass
|
|
|
|
def start(self):
|
|
# 启动逻辑
|
|
pass
|
|
|
|
def stop(self):
|
|
# 停止逻辑
|
|
pass
|
|
|
|
@property
|
|
def manifest(self):
|
|
return {
|
|
"name": "my-plugin",
|
|
"version": "1.0.0",
|
|
"dependencies": [],
|
|
"description": "我的插件"
|
|
}</code></pre>
|
|
|
|
<h2>关键原则</h2>
|
|
<ul>
|
|
<li>插件通过 <code>from oss.plugin.types import Plugin</code> 使用框架定义的接口</li>
|
|
<li>插件的 <code>main.py</code> 被 <code>importlib</code> 加载到框架的 Python 进程中</li>
|
|
<li>插件可以直接 <code>from oss.xxx import xxx</code> 引用框架模块</li>
|
|
<li>所有插件通过 <code>config.json</code> 配置,不修改源码</li>
|
|
</ul>
|
|
|
|
<h2>依赖声明</h2>
|
|
<pre><code>// manifest.json
|
|
{
|
|
"name": "html-render",
|
|
"version": "1.0.0",
|
|
"dependencies": ["http-api", "plugin-storage"],
|
|
"description": "HTML 渲染插件"
|
|
}</code></pre>
|
|
|
|
<p>框架会自动调用 <code>set_http_api()</code> 和 <code>set_plugin_storage()</code> 注入依赖实例。</p>
|
|
|
|
<h2>安装格式</h2>
|
|
<p>格式为 <code>@{作者名称}/插件名称</code>,例如 <code>@{Falck}/html-render</code>。</p>
|
|
</article>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<a href="https://gitee.com/starlight-apk/feature-oss/wikis" target="_blank" class="docs-wiki-btn">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/>
|
|
</svg>
|
|
<span>获取更多信息</span>
|
|
</a>
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
|
|
<script src="../js/dock.js"></script>
|
|
<script src="../js/particles.js"></script>
|
|
<script src="../js/parallax.js"></script>
|
|
<script src="../js/animations.js"></script>
|
|
<script>
|
|
// 汉堡菜单交互逻辑
|
|
(function() {
|
|
const hamburger = document.getElementById('docs-hamburger');
|
|
const sidebar = document.getElementById('docs-sidebar');
|
|
const overlay = document.getElementById('docs-overlay');
|
|
|
|
if (!hamburger || !sidebar || !overlay) return;
|
|
|
|
function openSidebar() {
|
|
sidebar.classList.add('is-open');
|
|
overlay.classList.add('is-visible');
|
|
hamburger.classList.add('is-active');
|
|
document.body.style.overflow = 'hidden';
|
|
}
|
|
|
|
function closeSidebar() {
|
|
sidebar.classList.remove('is-open');
|
|
overlay.classList.remove('is-visible');
|
|
hamburger.classList.remove('is-active');
|
|
document.body.style.overflow = ''';
|
|
}
|
|
|
|
function toggleSidebar() {
|
|
if (sidebar.classList.contains('is-open')) {
|
|
closeSidebar();
|
|
} else {
|
|
openSidebar();
|
|
}
|
|
}
|
|
|
|
hamburger.addEventListener('click', toggleSidebar);
|
|
overlay.addEventListener('click', closeSidebar);
|
|
|
|
sidebar.querySelectorAll('.docs-nav-item).forEach(link => {
|
|
link.addEventListener('click', closeSidebar);
|
|
});
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape' && sidebar.classList.contains('is-open')) {
|
|
closeSidebar();
|
|
}
|
|
});
|
|
|
|
let resizeTimer;
|
|
window.addEventListener('resize', () => {
|
|
clearTimeout(resizeTimer);
|
|
resizeTimer = setTimeout(() => {
|
|
if (window.innerWidth > 768 && sidebar.classList.contains('is-open')) {
|
|
closeSidebar();
|
|
}
|
|
}, 100);
|
|
});
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|