mirror of
https://github.com/lkddi/Xboard.git
synced 2026-04-28 06:47:24 +08:00
feat: new xboard
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Plugin;
|
||||
|
||||
abstract class AbstractPlugin
|
||||
{
|
||||
protected array $config = [];
|
||||
|
||||
/**
|
||||
* 插件启动时调用
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
// 子类实现具体逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件禁用时调用
|
||||
*/
|
||||
public function cleanup(): void
|
||||
{
|
||||
// 子类实现具体逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置配置
|
||||
*/
|
||||
public function setConfig(array $config): void
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置
|
||||
*/
|
||||
public function getConfig(): array
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册事件监听器
|
||||
*/
|
||||
protected function listen(string $hook, callable $callback): void
|
||||
{
|
||||
HookManager::register($hook, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除事件监听器
|
||||
*/
|
||||
protected function removeListener(string $hook): void
|
||||
{
|
||||
HookManager::remove($hook);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Plugin;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
|
||||
class HookManager
|
||||
{
|
||||
/**
|
||||
* 触发钩子
|
||||
*
|
||||
* @param string $hook 钩子名称
|
||||
* @param mixed $payload 传递给钩子的数据
|
||||
* @return mixed
|
||||
*/
|
||||
public static function call(string $hook, mixed $payload = null): mixed
|
||||
{
|
||||
return Event::dispatch($hook, [$payload]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册钩子监听器
|
||||
*
|
||||
* @param string $hook 钩子名称
|
||||
* @param callable $callback 回调函数
|
||||
* @return void
|
||||
*/
|
||||
public static function register(string $hook, callable $callback): void
|
||||
{
|
||||
Event::listen($hook, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除钩子监听器
|
||||
*
|
||||
* @param string $hook 钩子名称
|
||||
* @return void
|
||||
*/
|
||||
public static function remove(string $hook): void
|
||||
{
|
||||
Event::forget($hook);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Plugin;
|
||||
|
||||
use App\Models\Plugin;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class PluginConfigService
|
||||
{
|
||||
/**
|
||||
* 获取插件配置
|
||||
*
|
||||
* @param string $pluginCode
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig(string $pluginCode): array
|
||||
{
|
||||
$defaultConfig = $this->getDefaultConfig($pluginCode);
|
||||
if (empty($defaultConfig)) {
|
||||
return [];
|
||||
}
|
||||
$dbConfig = $this->getDbConfig($pluginCode);
|
||||
|
||||
$result = [];
|
||||
foreach ($defaultConfig as $key => $item) {
|
||||
$result[$key] = [
|
||||
'type' => $item['type'],
|
||||
'label' => $item['label'] ?? '',
|
||||
'placeholder' => $item['placeholder'] ?? '',
|
||||
'description' => $item['description'] ?? '',
|
||||
'value' => $dbConfig[$key] ?? $item['default']
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新插件配置
|
||||
*
|
||||
* @param string $pluginCode
|
||||
* @param array $config
|
||||
* @return bool
|
||||
*/
|
||||
public function updateConfig(string $pluginCode, array $config): bool
|
||||
{
|
||||
$defaultConfig = $this->getDefaultConfig($pluginCode);
|
||||
if (empty($defaultConfig)) {
|
||||
throw new \Exception('插件配置结构不存在');
|
||||
}
|
||||
$values = [];
|
||||
foreach ($config as $key => $value) {
|
||||
if (!isset($defaultConfig[$key])) {
|
||||
continue;
|
||||
}
|
||||
$values[$key] = $value;
|
||||
}
|
||||
Plugin::query()
|
||||
->where('code', $pluginCode)
|
||||
->update([
|
||||
'config' => json_encode($values),
|
||||
'updated_at' => now()
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件默认配置
|
||||
*
|
||||
* @param string $pluginCode
|
||||
* @return array
|
||||
*/
|
||||
protected function getDefaultConfig(string $pluginCode): array
|
||||
{
|
||||
$configFile = base_path("plugins/{$pluginCode}/config.json");
|
||||
if (!File::exists($configFile)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$config = json_decode(File::get($configFile), true);
|
||||
return $config['config'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库中的配置
|
||||
*
|
||||
* @param string $pluginCode
|
||||
* @return array
|
||||
*/
|
||||
protected function getDbConfig(string $pluginCode): array
|
||||
{
|
||||
$plugin = Plugin::query()
|
||||
->where('code', $pluginCode)
|
||||
->first();
|
||||
|
||||
if (!$plugin || empty($plugin->config)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return json_decode($plugin->config, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Plugin;
|
||||
|
||||
use App\Models\Plugin;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class PluginManager
|
||||
{
|
||||
protected string $pluginPath;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->pluginPath = base_path('plugins');
|
||||
}
|
||||
|
||||
/**
|
||||
* 安装插件
|
||||
*/
|
||||
public function install(string $pluginCode): bool
|
||||
{
|
||||
$configFile = $this->pluginPath . '/' . $pluginCode . '/config.json';
|
||||
|
||||
if (!File::exists($configFile)) {
|
||||
throw new \Exception('Plugin config file not found');
|
||||
}
|
||||
|
||||
$config = json_decode(File::get($configFile), true);
|
||||
if (!$this->validateConfig($config)) {
|
||||
throw new \Exception('Invalid plugin config');
|
||||
}
|
||||
|
||||
// 检查依赖
|
||||
if (!$this->checkDependencies($config['require'] ?? [])) {
|
||||
throw new \Exception('Dependencies not satisfied');
|
||||
}
|
||||
|
||||
// 提取配置默认值
|
||||
$defaultValues = [];
|
||||
if (isset($config['config']) && is_array($config['config'])) {
|
||||
foreach ($config['config'] as $key => $item) {
|
||||
$defaultValues[$key] = $item['default'] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
// 注册到数据库
|
||||
Plugin::create([
|
||||
'code' => $pluginCode,
|
||||
'name' => $config['name'],
|
||||
'version' => $config['version'],
|
||||
'is_enabled' => false,
|
||||
'config' => json_encode($defaultValues),
|
||||
'installed_at' => now(),
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用插件
|
||||
*/
|
||||
public function enable(string $pluginCode): bool
|
||||
{
|
||||
$plugin = $this->loadPlugin($pluginCode);
|
||||
if (!$plugin) {
|
||||
throw new \Exception('Plugin not found');
|
||||
}
|
||||
|
||||
// 获取插件配置
|
||||
$dbPlugin = Plugin::query()
|
||||
->where('code', $pluginCode)
|
||||
->first();
|
||||
|
||||
if ($dbPlugin && !empty($dbPlugin->config)) {
|
||||
$plugin->setConfig(json_decode($dbPlugin->config, true));
|
||||
}
|
||||
|
||||
// 更新数据库状态
|
||||
Plugin::query()
|
||||
->where('code', $pluginCode)
|
||||
->update([
|
||||
'is_enabled' => true,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
// 加载路由
|
||||
$routesFile = $this->pluginPath . '/' . $pluginCode . '/routes/web.php';
|
||||
if (File::exists($routesFile)) {
|
||||
require $routesFile;
|
||||
}
|
||||
|
||||
// 初始化插件
|
||||
if (method_exists($plugin, 'boot')) {
|
||||
$plugin->boot();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用插件
|
||||
*/
|
||||
public function disable(string $pluginCode): bool
|
||||
{
|
||||
$plugin = $this->loadPlugin($pluginCode);
|
||||
if (!$plugin) {
|
||||
throw new \Exception('Plugin not found');
|
||||
}
|
||||
|
||||
// 更新数据库状态
|
||||
Plugin::query()
|
||||
->where('code', $pluginCode)
|
||||
->update([
|
||||
'is_enabled' => false,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
// 清理插件
|
||||
if (method_exists($plugin, 'cleanup')) {
|
||||
$plugin->cleanup();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 卸载插件
|
||||
*/
|
||||
public function uninstall(string $pluginCode): bool
|
||||
{
|
||||
// 先禁用插件
|
||||
$this->disable($pluginCode);
|
||||
|
||||
// 删除数据库记录
|
||||
Plugin::query()->where('code', $pluginCode)->delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载插件实例
|
||||
*/
|
||||
protected function loadPlugin(string $pluginCode)
|
||||
{
|
||||
$pluginFile = $this->pluginPath . '/' . $pluginCode . '/Plugin.php';
|
||||
if (!File::exists($pluginFile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
require_once $pluginFile;
|
||||
$className = "Plugin\\{$pluginCode}\\Plugin";
|
||||
return new $className();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证配置文件
|
||||
*/
|
||||
protected function validateConfig(array $config): bool
|
||||
{
|
||||
return isset($config['code'])
|
||||
&& isset($config['version'])
|
||||
&& isset($config['description'])
|
||||
&& isset($config['author']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查依赖关系
|
||||
*/
|
||||
protected function checkDependencies(array $requires): bool
|
||||
{
|
||||
foreach ($requires as $package => $version) {
|
||||
if ($package === 'xboard') {
|
||||
// 检查xboard版本
|
||||
// 实现版本比较逻辑
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user