可道云的插件系统工作原理
-
插件系统架构:
- 插件系统采用基于钩子(Hook)的架构
- 每个插件都继承自
PluginBase基类 - 插件通过注册钩子来扩展系统功能
-
插件目录结构:
plugins/ ├── pluginName/ │ ├── app.php # 插件主类文件 │ ├── static/ # 静态资源 │ ├── php/ # PHP 类文件 │ └── package.json # 插件配置文件 -
插件生命周期:
- 安装:通过
adminPlugin->install()方法处理 - 启用/禁用:通过
adminPlugin->changeStatus()方法控制 - 卸载:通过
adminPlugin->unInstall()方法处理
- 安装:通过
-
插件注册机制:
public function regist(){ $this->hookRegist(array( 'user.commonJs.insert' => 'pluginName.echoJs', // 其他钩子... )); } -
钩子系统:
- 系统预定义了多个钩子点,如:
user.commonJs.insert:插入公共 JSglobalRequest:全局请求处理admin.storage.add.before:存储添加前explorer.kodApp.before:应用列表加载前
- 系统预定义了多个钩子点,如:
-
插件权限控制:
public function checkAuth($appName){ $plugin = Model("Plugin")->loadList($appName); if (!$plugin) return true; if ($plugin['status'] == 0) return false; // 权限检查逻辑... } -
插件配置管理:
- 每个插件可以有自己的配置文件
- 通过
getConfig()方法获取配置 - 配置项在
package.json中定义
-
插件开发示例:
class examplePlugin extends PluginBase { function __construct(){ parent::__construct(); } public function regist(){ $this->hookRegist(array( 'user.commonJs.insert' => 'examplePlugin.echoJs', )); } public function echoJs(){ $this->echoFile('static/main.js'); } } -
插件与前端交互:
kodReady.push(function(){ Events.bind('explorer.kodApp.before',function(appList){ appList.push({ name: '{{package.id}}', title: '{{package.name}}', ext: "{{config.fileExt}}", // 其他配置... }); }); }); -
插件安全机制:
- 插件权限检查
- 插件状态管理
- 插件配置验证
- 插件依赖检查
要开发一个插件,您需要:
- 创建插件目录结构
- 实现
app.php主类文件 - 在
regist()方法中注册需要的钩子 - 实现钩子对应的处理方法
- 添加必要的静态资源
- 配置
package.json
url访问
[domain]/?plugin/md5Opener/test
SSE连接
// 建立 SSE 连接
const eventSource = new EventSource("/?plugin/md5Opener/test");
// 接收消息
eventSource.onmessage = function (event) {
console.log("收到SSE消息:", event.data);
// 如果页面有messages元素则显示消息
const msgDiv = document.getElementById("messages");
if (msgDiv) {
msgDiv.innerHTML += `<p>${event.data}</p>`;
}
};
// 连接打开时
eventSource.onopen = function () {
console.log("SSE 连接已建立");
};
// 连接错误时
eventSource.onerror = function (err) {
console.error("SSE 错误", err);
// 尝试重新连接
if (eventSource.readyState === EventSource.CLOSED) {
console.log("SSE 连接已关闭");
}
};
// 处理自定义结束事件
eventSource.addEventListener('end', function(event) {
console.log("SSE 连接正常结束:", event.data);
eventSource.close();
});public function test()
{
// 设置 SSE 的响应头
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Connection: keep-alive");
header("Access-Control-Allow-Origin: *"); // 允许跨域请求
header("X-Accel-Buffering: no"); // 禁用nginx缓冲
// 禁止超时
set_time_limit(0);
// 清除输出缓冲区
if (ob_get_level()) {
ob_end_clean();
}
$counter = 0;
while (true) {
$counter++;
$time = date("Y-m-d H:i:s");
// SSE 格式:必须以 "data:" 开头,以两个换行结尾
echo "data: 当前时间是 {$time}, 次数 {$counter}\n\n";
// 把数据立即推送给客户端
if (@ob_get_level()) {
@ob_flush();
}
flush();
// 检查连接是否断开
if (connection_aborted()) {
break;
}
// 每 2 秒推送一次
sleep(2);
}
// 正常结束时发送结束标识
echo "event: end\ndata: 连接已关闭\n\n";
if (@ob_get_level()) {
@ob_flush();
}
flush();
}