mirror of
https://github.com/crystelf/crystelf-core.git
synced 2025-10-14 05:19:19 +00:00
小改
This commit is contained in:
parent
d43b05bae5
commit
92e034b57c
2
pnpm-workspace.yaml
Normal file
2
pnpm-workspace.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
- 'src/plugins/*'
|
60
src/core/app/core.ts
Normal file
60
src/core/app/core.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
class Core {
|
||||||
|
private static _instance: Core;
|
||||||
|
private _services: Map<string, any> = new Map();
|
||||||
|
[key: string]: any;
|
||||||
|
private constructor() {}
|
||||||
|
|
||||||
|
public static get logger() {
|
||||||
|
return Core.getInstance()._services.get('logger');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get redis() {
|
||||||
|
return Core.getInstance()._services.get('redis');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get ws() {
|
||||||
|
return Core.getInstance()._services.get('ws');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get tools() {
|
||||||
|
return Core.getInstance()._services.get('tools');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get system() {
|
||||||
|
return Core.getInstance()._services.get('system');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get response() {
|
||||||
|
return Core.getInstance()._services.get('response');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get file() {
|
||||||
|
return Core.getInstance()._services.get('file');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册服务
|
||||||
|
* @param name 服务名称
|
||||||
|
* @param service 服务
|
||||||
|
*/
|
||||||
|
public static registerService(name: string, service: any): void {
|
||||||
|
Core.getInstance()._services.set(name, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getInstance(): Core {
|
||||||
|
if (!Core._instance) {
|
||||||
|
Core._instance = new Core();
|
||||||
|
}
|
||||||
|
return Core._instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否有某个依赖
|
||||||
|
* @param name 依赖名
|
||||||
|
*/
|
||||||
|
public static hasService(name: string): boolean {
|
||||||
|
return Core.getInstance()._services.has(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Core;
|
@ -3,9 +3,10 @@ import fs from 'fs/promises';
|
|||||||
import simpleGit, { SimpleGit } from 'simple-git';
|
import simpleGit, { SimpleGit } from 'simple-git';
|
||||||
import { Application } from 'express';
|
import { Application } from 'express';
|
||||||
import { Server } from 'http';
|
import { Server } from 'http';
|
||||||
import Plugin from '../types/plugin';
|
import Plugin from './../types/plugin';
|
||||||
import logger from '../utils/system/logger';
|
import logger from '../utils/system/logger';
|
||||||
import paths from '../utils/system/path';
|
import paths from '../utils/system/path';
|
||||||
|
import Core from './core';
|
||||||
|
|
||||||
class PluginLoader {
|
class PluginLoader {
|
||||||
private readonly pluginsDir: string;
|
private readonly pluginsDir: string;
|
||||||
@ -21,11 +22,13 @@ class PluginLoader {
|
|||||||
|
|
||||||
public async loadPlugins(): Promise<void> {
|
public async loadPlugins(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
logger.info('正在加载插件..');
|
||||||
const pluginFolders = await fs.readdir(this.pluginsDir);
|
const pluginFolders = await fs.readdir(this.pluginsDir);
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
pluginFolders.map(async (folder) => {
|
pluginFolders.map(async (folder) => {
|
||||||
const pluginPath = path.join(this.pluginsDir, folder);
|
const pluginPath = path.join(this.pluginsDir, folder);
|
||||||
|
logger.debug(`加载${folder}插件..`);
|
||||||
const stat = await fs.stat(pluginPath);
|
const stat = await fs.stat(pluginPath);
|
||||||
|
|
||||||
if (stat.isDirectory()) {
|
if (stat.isDirectory()) {
|
||||||
@ -40,6 +43,11 @@ class PluginLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载插件
|
||||||
|
* @param pluginPath
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
private async loadPlugin(pluginPath: string): Promise<void> {
|
private async loadPlugin(pluginPath: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const pluginName = path.basename(pluginPath);
|
const pluginName = path.basename(pluginPath);
|
||||||
@ -63,6 +71,13 @@ class PluginLoader {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.checkDependencies(plugin);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`插件依赖检查失败: ${plugin.name}`, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (plugin.initialize) {
|
if (plugin.initialize) {
|
||||||
await plugin.initialize(this.app, this.server);
|
await plugin.initialize(this.app, this.server);
|
||||||
}
|
}
|
||||||
@ -78,6 +93,11 @@ class PluginLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查更新
|
||||||
|
* @param pluginPath
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
private async checkPluginUpdates(pluginPath: string): Promise<boolean> {
|
private async checkPluginUpdates(pluginPath: string): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const git = simpleGit(pluginPath);
|
const git = simpleGit(pluginPath);
|
||||||
@ -99,6 +119,11 @@ class PluginLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新插件
|
||||||
|
* @param pluginPath
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
private async updatePlugin(pluginPath: string): Promise<void> {
|
private async updatePlugin(pluginPath: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const git = this.gitInstances.get(pluginPath);
|
const git = this.gitInstances.get(pluginPath);
|
||||||
@ -116,6 +141,25 @@ class PluginLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查依赖
|
||||||
|
* @param plugin
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private async checkDependencies(plugin: Plugin): Promise<boolean> {
|
||||||
|
if (!plugin.dependencies) return true;
|
||||||
|
|
||||||
|
for (const dep of plugin.dependencies) {
|
||||||
|
if (!Core.hasService(dep)) {
|
||||||
|
throw new Error(`插件 ${plugin.name} 缺少依赖服务: ${dep}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭插件
|
||||||
|
*/
|
||||||
public async closePlugins(): Promise<void> {
|
public async closePlugins(): Promise<void> {
|
||||||
await this.invokePluginHooks('onClose');
|
await this.invokePluginHooks('onClose');
|
||||||
this.loadedPlugins.clear();
|
this.loadedPlugins.clear();
|
||||||
|
@ -1,22 +1,33 @@
|
|||||||
import { Application } from 'express';
|
import { Application } from 'express';
|
||||||
import { Server } from 'http';
|
import { Server } from 'http';
|
||||||
|
|
||||||
interface Plugin {
|
export default interface Plugin {
|
||||||
|
// 必须字段
|
||||||
name: string;
|
name: string;
|
||||||
version: string;
|
version: string;
|
||||||
|
|
||||||
|
// 可选描述
|
||||||
description?: string;
|
description?: string;
|
||||||
// 初始化插件
|
|
||||||
|
// 依赖的核心服务 (如 ['logger', 'redis'])
|
||||||
|
dependencies?: string[];
|
||||||
|
|
||||||
|
// 初始化方法
|
||||||
initialize?: (app: Application, server?: Server) => void | Promise<void>;
|
initialize?: (app: Application, server?: Server) => void | Promise<void>;
|
||||||
// 路由挂载点
|
|
||||||
|
// 路由注册方法
|
||||||
routes?: (app: Application) => void;
|
routes?: (app: Application) => void;
|
||||||
|
|
||||||
// 生命周期钩子
|
// 生命周期钩子
|
||||||
onReady?: () => void | Promise<void>;
|
onReady?: () => void | Promise<void>;
|
||||||
onClose?: () => void | Promise<void>;
|
onClose?: () => void | Promise<void>;
|
||||||
onError?: (error: Error) => void;
|
onError?: (error: Error) => void;
|
||||||
// 自动更新相关
|
|
||||||
|
// 自动更新配置
|
||||||
autoUpdateEnabled?: boolean;
|
autoUpdateEnabled?: boolean;
|
||||||
checkForUpdates?: () => Promise<boolean>;
|
checkForUpdates?: () => Promise<boolean>;
|
||||||
applyUpdate?: () => Promise<void>;
|
applyUpdate?: () => Promise<void>;
|
||||||
}
|
|
||||||
|
|
||||||
export default Plugin;
|
// 其他配置
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
26
src/plugins/example/index.ts
Normal file
26
src/plugins/example/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import Plugin from '../../core/types/plugin';
|
||||||
|
import MainService from './main.service';
|
||||||
|
import Core from './../../core/app/core';
|
||||||
|
|
||||||
|
const plugin: Plugin = {
|
||||||
|
name: 'example',
|
||||||
|
version: '1.0.0',
|
||||||
|
dependencies: ['logger'],
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
this.service = new MainService();
|
||||||
|
Core.registerService('example', this.service);
|
||||||
|
},
|
||||||
|
|
||||||
|
routes(app) {
|
||||||
|
app.get('/api/example', (req, res) => {
|
||||||
|
Core.response.success(res, { message: 'Hello from plugin' });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onClose() {
|
||||||
|
this.service.cleanup();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default plugin;
|
7
src/plugins/example/main.service.ts
Normal file
7
src/plugins/example/main.service.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import logger from '../../core/utils/system/logger';
|
||||||
|
|
||||||
|
export default class MainService {
|
||||||
|
constructor() {
|
||||||
|
logger.info('示例插件初始化..');
|
||||||
|
}
|
||||||
|
}
|
10
src/plugins/example/package.json
Normal file
10
src/plugins/example/package.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "plugin-name",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"crystelf": {
|
||||||
|
"type": "plugin",
|
||||||
|
"dependencies": []
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,9 @@
|
|||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"outDir": "dist"
|
"outDir": "dist",
|
||||||
|
"rootDir": ".",
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src/**/*", "src/plugins/**/*"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user