Init: Create & Init ms Project...
Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
		
							
								
								
									
										4
									
								
								packages/plugin/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								packages/plugin/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
/node_modules
 | 
			
		||||
/dist
 | 
			
		||||
/package-lock.json
 | 
			
		||||
/yarn.lock
 | 
			
		||||
							
								
								
									
										22
									
								
								packages/plugin/.npmignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								packages/plugin/.npmignore
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
src
 | 
			
		||||
test
 | 
			
		||||
typings
 | 
			
		||||
bundled
 | 
			
		||||
build
 | 
			
		||||
coverage
 | 
			
		||||
docs
 | 
			
		||||
wiki
 | 
			
		||||
gulpfile.js
 | 
			
		||||
bower.json
 | 
			
		||||
karma.conf.js
 | 
			
		||||
tsconfig.json
 | 
			
		||||
typings.json
 | 
			
		||||
CONTRIBUTING.md
 | 
			
		||||
ISSUE_TEMPLATE.md
 | 
			
		||||
PULL_REQUEST_TEMPLATE.md
 | 
			
		||||
tslint.json
 | 
			
		||||
wallaby.js
 | 
			
		||||
.travis.yml
 | 
			
		||||
.gitignore
 | 
			
		||||
.vscode
 | 
			
		||||
type_definitions
 | 
			
		||||
							
								
								
									
										34
									
								
								packages/plugin/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								packages/plugin/package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@ms/plugin",
 | 
			
		||||
    "version": "0.0.0",
 | 
			
		||||
    "description": "MiaoScript api package",
 | 
			
		||||
    "keywords": [
 | 
			
		||||
        "miaoscript",
 | 
			
		||||
        "minecraft",
 | 
			
		||||
        "bukkit",
 | 
			
		||||
        "sponge"
 | 
			
		||||
    ],
 | 
			
		||||
    "author": "MiaoWoo <admin@yumc.pw>",
 | 
			
		||||
    "homepage": "https://github.com/circlecloud/ms.git",
 | 
			
		||||
    "license": "ISC",
 | 
			
		||||
    "main": "dist/index.js",
 | 
			
		||||
    "publishConfig": {
 | 
			
		||||
        "registry": "https://repo.yumc.pw/repository/npm/"
 | 
			
		||||
    },
 | 
			
		||||
    "scripts": {
 | 
			
		||||
        "clean": "rimraf dist",
 | 
			
		||||
        "watch": "npx tsc --watch",
 | 
			
		||||
        "build": "yarn clean && npx tsc",
 | 
			
		||||
        "test": "echo \"Error: run tests from root\" && exit 1"
 | 
			
		||||
    },
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "reflect-metadata": "^0.1.13",
 | 
			
		||||
        "rimraf": "^3.0.0",
 | 
			
		||||
        "typescript": "^3.6.2"
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@ms/api": "^0.0.0",
 | 
			
		||||
        "es6-map": "^0.1.5",
 | 
			
		||||
        "inversify": "^5.0.1"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								packages/plugin/src/constants.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								packages/plugin/src/constants.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
export const METADATA_KEY = {
 | 
			
		||||
    plugin: "@ms/plugin:plugin",
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										20
									
								
								packages/plugin/src/decorators.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								packages/plugin/src/decorators.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
import { interfaces } from './interfaces'
 | 
			
		||||
import { METADATA_KEY } from './constants'
 | 
			
		||||
import { injectable, decorate } from "inversify";
 | 
			
		||||
import { getPluginMetadatas } from './utils'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MiaoScript plugin
 | 
			
		||||
 * @param name namespace name default is '/'
 | 
			
		||||
 * @param middleware middleware array
 | 
			
		||||
 */
 | 
			
		||||
export function plugin(currentMetadata: interfaces.PluginMetadata) {
 | 
			
		||||
    return function(target: any) {
 | 
			
		||||
        target.description = currentMetadata;
 | 
			
		||||
        currentMetadata.target = target;
 | 
			
		||||
        decorate(injectable(), target);
 | 
			
		||||
        Reflect.defineMetadata(METADATA_KEY.plugin, currentMetadata, target);
 | 
			
		||||
        const previousMetadata: interfaces.PluginMetadata[] = getPluginMetadatas();
 | 
			
		||||
        Reflect.defineMetadata(METADATA_KEY.plugin, [currentMetadata, ...previousMetadata], Reflect);
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								packages/plugin/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								packages/plugin/src/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
export * from './manager'
 | 
			
		||||
export * from './decorators'
 | 
			
		||||
export * from './interfaces'
 | 
			
		||||
							
								
								
									
										25
									
								
								packages/plugin/src/interfaces.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								packages/plugin/src/interfaces.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
import { injectable, postConstruct } from "inversify";
 | 
			
		||||
import { getPluginMetadata } from './utils'
 | 
			
		||||
 | 
			
		||||
export namespace interfaces {
 | 
			
		||||
    @injectable()
 | 
			
		||||
    export abstract class Plugin {
 | 
			
		||||
        public description: PluginMetadata;
 | 
			
		||||
        protected logger: Console;
 | 
			
		||||
 | 
			
		||||
        @postConstruct()
 | 
			
		||||
        private init() {
 | 
			
		||||
            this.logger = global.console;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public load() { }
 | 
			
		||||
        public enable() { }
 | 
			
		||||
        public disable() { }
 | 
			
		||||
    }
 | 
			
		||||
    export interface PluginMetadata {
 | 
			
		||||
        name: string;
 | 
			
		||||
        version: string;
 | 
			
		||||
        author: string | string[];
 | 
			
		||||
        target?: any;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										136
									
								
								packages/plugin/src/manager.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								packages/plugin/src/manager.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
import { plugin, server } from '@ms/api'
 | 
			
		||||
import { injectable, inject, postConstruct, Container } from '@ms/container'
 | 
			
		||||
import * as fs from '@ms/common/dist/fs'
 | 
			
		||||
 | 
			
		||||
import { getPluginMetadatas } from './utils'
 | 
			
		||||
import { interfaces } from './interfaces';
 | 
			
		||||
 | 
			
		||||
@injectable()
 | 
			
		||||
export class PluginManagerImpl implements plugin.PluginManager {
 | 
			
		||||
    @inject(plugin.PluginInstance)
 | 
			
		||||
    private pluginInstance: any;
 | 
			
		||||
    @inject(server.ServerType)
 | 
			
		||||
    private serverType: string;
 | 
			
		||||
 | 
			
		||||
    private pluginMap: Map<string, interfaces.Plugin>;
 | 
			
		||||
 | 
			
		||||
    @postConstruct()
 | 
			
		||||
    init() {
 | 
			
		||||
        if (this.pluginInstance !== null) {
 | 
			
		||||
            // 如果plugin不等于null 则代表是正式环境
 | 
			
		||||
            console.info(`Initialization MiaoScript Plugin System: ${this.pluginInstance} ...`);
 | 
			
		||||
            this.pluginMap = new Map();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    scan(folder: string): void {
 | 
			
		||||
        var plugin = fs.file(root, folder);
 | 
			
		||||
        var files = []
 | 
			
		||||
            // load common plugin
 | 
			
		||||
            .concat(this.scanFloder(plugin))
 | 
			
		||||
            // load space plugin
 | 
			
		||||
            .concat(this.scanFloder(fs.file(plugin, this.serverType)))
 | 
			
		||||
        this.loadPlugins(files);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    load(container: Container): void {
 | 
			
		||||
        this.buildPlugins(container);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enable(): void {
 | 
			
		||||
        this.pluginMap.forEach(pl => this.runCatch(pl, 'load'));
 | 
			
		||||
        this.pluginMap.forEach(pl => this.runCatch(pl, 'enable'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    disable(): void {
 | 
			
		||||
        throw new Error("Method not implemented.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private runCatch(pl: any, func: string) {
 | 
			
		||||
        console.log(JSON.stringify(pl));
 | 
			
		||||
        try {
 | 
			
		||||
            pl[func].call(pl);
 | 
			
		||||
        } catch (ex) {
 | 
			
		||||
            console.console(`§6插件 §b${pl.description.name} §6执行 §d${func} §6方法时发生错误 §4${ex}`);
 | 
			
		||||
            console.ex(ex);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private scanFloder(plugin: any): string[] {
 | 
			
		||||
        var files = [];
 | 
			
		||||
        console.info(`Start Scan Plugins in ${plugin} ...`);
 | 
			
		||||
        this.checkUpdateFolder(plugin);
 | 
			
		||||
        fs.list(plugin).forEach(function searchPlugin(file) {
 | 
			
		||||
            files.push(file.toFile());
 | 
			
		||||
        });
 | 
			
		||||
        return files;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新插件
 | 
			
		||||
     * @param path
 | 
			
		||||
     */
 | 
			
		||||
    private checkUpdateFolder(path) {
 | 
			
		||||
        var update = fs.file(path, "update");
 | 
			
		||||
        if (!update.exists()) {
 | 
			
		||||
            update.mkdirs();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private loadPlugins(files: any[]): void {
 | 
			
		||||
        this.loadJsPlugins(files);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
    * JS类型插件预加载
 | 
			
		||||
    */
 | 
			
		||||
    private loadJsPlugins(files: any[]) {
 | 
			
		||||
        files.filter(file => file.name.endsWith(".js")).forEach(file => {
 | 
			
		||||
            try {
 | 
			
		||||
                this.loadPlugin(file)
 | 
			
		||||
            } catch (ex) {
 | 
			
		||||
                console.console(`§6插件 §b${file.name} §6初始化时发生错误 §4${ex.message}`);
 | 
			
		||||
                console.ex(ex);
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private loadPlugin(file: any) {
 | 
			
		||||
        this.updatePlugin(file);
 | 
			
		||||
        this.createPlugin(file);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private updatePlugin(file: any) {
 | 
			
		||||
        var update = fs.file(fs.file(file.parentFile, 'update'), file.name);
 | 
			
		||||
        if (update.exists()) {
 | 
			
		||||
            console.info(`Auto Update Plugin ${file.name} ...`);
 | 
			
		||||
            fs.move(update, file, true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private createPlugin(file) {
 | 
			
		||||
        //@ts-ignore
 | 
			
		||||
        require(file, {
 | 
			
		||||
            cache: false
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private beforeLoadHook(origin) {
 | 
			
		||||
        var result = origin;
 | 
			
		||||
        // // 注入 console 对象         // 给插件注入单独的 console
 | 
			
		||||
        // result += '\nvar console = new Console(); module.exports.console = console;';
 | 
			
		||||
        // // 插件注入 self 对象
 | 
			
		||||
        // result += '\nvar self = {}; module.exports.self = self;';
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private buildPlugins(container: Container) {
 | 
			
		||||
        let pluginMetadatas = getPluginMetadatas();
 | 
			
		||||
        for (const metadata of pluginMetadatas) {
 | 
			
		||||
            container.bind(plugin.Plugin).to(metadata.target).inSingletonScope().whenTargetNamed(metadata.name);
 | 
			
		||||
            this.pluginMap.set(metadata.name, container.getNamed(plugin.Plugin, metadata.name));
 | 
			
		||||
            let pluginInstance = this.pluginMap.get(metadata.name)
 | 
			
		||||
            pluginInstance.description = metadata;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								packages/plugin/src/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								packages/plugin/src/utils.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
import { interfaces } from './interfaces'
 | 
			
		||||
import { METADATA_KEY } from './constants'
 | 
			
		||||
 | 
			
		||||
function getPlugins() {
 | 
			
		||||
    return getPluginMetadatas().map((target) => target.target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getPluginMetadatas() {
 | 
			
		||||
    let pluginMetadatas: interfaces.PluginMetadata[] = Reflect.getMetadata(
 | 
			
		||||
        METADATA_KEY.plugin,
 | 
			
		||||
        Reflect
 | 
			
		||||
    ) || [];
 | 
			
		||||
    return pluginMetadatas;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getPluginMetadata(target: any) {
 | 
			
		||||
    let pluginMetadata: interfaces.PluginMetadata = Reflect.getMetadata(
 | 
			
		||||
        METADATA_KEY.plugin,
 | 
			
		||||
        target
 | 
			
		||||
    ) || {};
 | 
			
		||||
    return pluginMetadata;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
    getPlugins,
 | 
			
		||||
    getPluginMetadatas,
 | 
			
		||||
    getPluginMetadata
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								packages/plugin/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								packages/plugin/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
    "extends": "../../tsconfig.json",
 | 
			
		||||
    "compilerOptions": {
 | 
			
		||||
        "baseUrl": "src",
 | 
			
		||||
        "outDir": "dist"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user