From 8d0484eefb9e3cb53d4241a21803383b2f61214f Mon Sep 17 00:00:00 2001 From: MiaoWoo Date: Mon, 25 Apr 2022 00:41:11 +0800 Subject: [PATCH] feat: add loadMavenDepend & optimize database Signed-off-by: MiaoWoo --- packages/container/src/decorators.ts | 31 +------------- packages/container/src/index.ts | 62 ++++++++++++++++++++++++++-- packages/container/src/utils.ts | 30 ++++++++++++++ packages/core/src/index.ts | 21 +++++++++- packages/database/src/database.ts | 29 +++++++------ packages/database/src/index.ts | 8 +++- packages/database/src/manager.ts | 36 +++++++--------- packages/nashorn/src/index.ts | 12 ++++++ packages/plugin/src/command.ts | 2 +- packages/plugin/src/index.ts | 2 + 10 files changed, 165 insertions(+), 68 deletions(-) create mode 100644 packages/container/src/utils.ts diff --git a/packages/container/src/decorators.ts b/packages/container/src/decorators.ts index 17789407..27bcc46e 100644 --- a/packages/container/src/decorators.ts +++ b/packages/container/src/decorators.ts @@ -1,38 +1,9 @@ import { interfaces, Container } from "inversify" +import { _proxyGetter } from "./utils" let _container: Container const ContainerInstance = Symbol.for("@ccms/ioc:Container") -const INJECTION = Symbol.for("INJECTION") - -function _proxyGetter( - proto: any, - key: string, - resolve: () => any, - doCache: boolean -) { - function getter(this: object) { - if (doCache && !Reflect.hasMetadata(INJECTION, this, key)) { - Reflect.defineMetadata(INJECTION, resolve(), this, key) - } - if (Reflect.hasMetadata(INJECTION, this, key)) { - return Reflect.getMetadata(INJECTION, this, key) - } else { - return resolve() - } - } - - function setter(this: object, newVal: any) { - Reflect.defineMetadata(INJECTION, newVal, this, key) - } - - Object.defineProperty(proto, key, { - configurable: true, - enumerable: true, - get: getter, - set: setter - }) -} function initContainer(container: Container) { Reflect.defineMetadata(ContainerInstance, container, Reflect) diff --git a/packages/container/src/index.ts b/packages/container/src/index.ts index 7cf9b536..b28045f3 100644 --- a/packages/container/src/index.ts +++ b/packages/container/src/index.ts @@ -5,6 +5,7 @@ import { initContainer, getContainer } from './decorators' import { interfaces, Container, inject, named } from 'inversify' import { fluentProvide } from 'inversify-binding-decorators' import { ioc } from "./constants" +import { _proxyGetter } from "./utils" /** * 注册一个命名对象 @@ -49,9 +50,11 @@ export const JavaClass = (className: string) => { */ export const JSClass = (className: string) => { return function (target: object, propertyKey: string, index?: number) { - try { target[propertyKey] = Java.type(className); return } catch (error: any) { } - try { target[propertyKey] = base.getClass(className).static; return } catch (error: any) { } - console.warn('JSClass', className, 'Inject target', target.constructor.name, 'propertyKey', propertyKey, 'failed!') + _proxyGetter(target, propertyKey, () => { + try { return Java.type(className) } catch (error: any) { } + try { return base.getClass(className).static } catch (error: any) { } + console.warn('JSClass', className, 'Inject target', target.constructor.name, 'propertyKey', propertyKey, 'failed!') + }, true) } } @@ -88,6 +91,59 @@ export const Resource = (resourceName?: string | any) => { } } +const DocumentBuilderFactory = Java.type('javax.xml.parsers.DocumentBuilderFactory') + +export const MavenDepend = (groupId: string, artifactId: string, version: string, recursion = false) => { + return function (target: any) { + loadMavenDepend(groupId, artifactId, version, recursion) + } +} + +const loadedMavenDepend = new Set() + +export function loadMavenDepend(groupId: string, artifactId: string, version: string, recursion = false) { + try { + const key = `${groupId}:${artifactId}:${version}` + if (loadedMavenDepend.has(key)) { return } + console.info('loading maven dependency', key) + let [pom, _] = base.loadMavenDepend(groupId, artifactId, version) + loadedMavenDepend.add(key) + if (recursion) { + let doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(pom) + let dependencies = doc.getElementsByTagName("dependency") + let size = dependencies.length + if (!size) { return } + console.info(key, 'found', size, 'dependencies loading...') + for (let i = 0; i < size; i++) { + const dependency = dependencies.item(i) + const gav = dependency.getChildNodes() + const length = gav.length + const dependencyVersion = { groupId: '', artifactId: '', version: '' } + for (let j = 0; j < length; j++) { + const prop = gav.item(j) + switch (prop.getNodeName()) { + case "groupId": + dependencyVersion.groupId = prop.getTextContent() + break + case "artifactId": + dependencyVersion.artifactId = prop.getTextContent() + break + case "version": + dependencyVersion.version = prop.getTextContent() + break + } + } + loadMavenDepend(dependencyVersion.groupId, dependencyVersion.artifactId, dependencyVersion.version, recursion) + } + } + } catch (error: any) { + console.warn('attachMavenDepend failed. Error: ' + error) + if (global.debug) { + console.ex(error) + } + } +} + export const reduceMetadata = (ctx: interfaces.Context): any => { return ctx.currentRequest.target.metadata.reduce((result, entry, index) => { result[entry.key] = entry.value diff --git a/packages/container/src/utils.ts b/packages/container/src/utils.ts new file mode 100644 index 00000000..33ccb56f --- /dev/null +++ b/packages/container/src/utils.ts @@ -0,0 +1,30 @@ +const INJECTION = Symbol.for("INJECTION") + +export function _proxyGetter( + proto: any, + key: string, + resolve: () => any, + doCache: boolean +) { + function getter(this: object) { + if (doCache && !Reflect.hasMetadata(INJECTION, this, key)) { + Reflect.defineMetadata(INJECTION, resolve(), this, key) + } + if (Reflect.hasMetadata(INJECTION, this, key)) { + return Reflect.getMetadata(INJECTION, this, key) + } else { + return resolve() + } + } + + function setter(this: object, newVal: any) { + Reflect.defineMetadata(INJECTION, newVal, this, key) + } + + Object.defineProperty(proto, key, { + configurable: true, + enumerable: true, + get: getter, + set: setter + }) +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 889ae65c..59a39a59 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -3,7 +3,11 @@ console.i18n("ms.core.ioc.initialize", { scope: global.scope }) import { plugin, server, task, constants } from '@ccms/api' import { DefaultContainer as container, provideSingleton, ContainerInstance, buildProviderModule, Autowired } from '@ccms/container' console.i18n("ms.core.ioc.completed", { scope: global.scope, time: (Date.now() - containerStartTime) / 1000 }) +import * as yaml from 'js-yaml' import http from '@ccms/common/dist/http' +import * as fs from '@ccms/common/dist/fs' + +const UUID = Java.type('java.util.UUID') @provideSingleton(MiaoScriptCore) class MiaoScriptCore { @@ -106,9 +110,24 @@ function loadCoreScript(name) { } } +function loadMiaoScriptConfig() { + let configFile = fs.concat(root, 'config.yml') + if (!fs.exists(configFile)) { + global.ScriptEngineConfig = base.save(configFile, yaml.dump({ + uuid: UUID.randomUUID().toString(), + channel: 'latest', + slow_execute: 50 + })) + } else { + global.ScriptEngineConfig = yaml.load(base.read(configFile)) + } + global.ScriptEngineChannel = global.ScriptEngineConfig.channel || 'latest' + global.ScriptSlowExecuteTime = global.ScriptEngineConfig.slow_execute || 50 +} + function initialize() { process.emit('core.before.initialize') - global.ScriptSlowExecuteTime = 50 + loadMiaoScriptConfig() global.ScriptEngineVersion = require('../package.json').version global.setGlobal('loadCoreScript', loadCoreScript) loadCoreScript('initialize') diff --git a/packages/database/src/database.ts b/packages/database/src/database.ts index 160225b8..07c5c936 100644 --- a/packages/database/src/database.ts +++ b/packages/database/src/database.ts @@ -1,9 +1,6 @@ +import { JSClass } from '@ccms/container' import { Model } from './model' -const HikariDataSource = Java.type('com.zaxxer.hikari.HikariDataSource') -const HikariConfig = Java.type('com.zaxxer.hikari.HikariConfig') -const JdbcTemplate = Java.type('org.springframework.jdbc.core.JdbcTemplate') - /** * 数据库配置 */ @@ -33,6 +30,13 @@ export class DataBase { private dataSource: javax.sql.DataSource private jdbcTemplate: org.springframework.jdbc.core.JdbcTemplate + @JSClass('com.zaxxer.hikari.HikariDataSource') + private HikariDataSource: any + @JSClass('com.zaxxer.hikari.HikariConfig') + private HikariConfig: any + @JSClass('org.springframework.jdbc.core.JdbcTemplate') + private JdbcTemplate: typeof org.springframework.jdbc.core.JdbcTemplate + constructor(dbConfig: DataBaseConfig) { if (!dbConfig.url) { throw new Error('DataBase url can\'t be null!') } this.createDataSource(dbConfig) @@ -41,24 +45,25 @@ export class DataBase { private createDataSource(dbConfig: DataBaseConfig) { if (typeof dbConfig.url === "string") { - if (!dbConfig.username || !dbConfig.password) { - throw new Error('DataBase username or password can\'t be null!') - } - let config = new HikariConfig() + let config = new this.HikariConfig() if (dbConfig.driverClassName) { config.setDriverClassName(dbConfig.driverClassName) } - config.setUsername(dbConfig.username) - config.setPassword(dbConfig.password) + if (dbConfig.username) { + config.setUsername(dbConfig.username) + } + if (dbConfig.password) { + config.setPassword(dbConfig.password) + } config.setJdbcUrl(dbConfig.url) - this.dataSource = new HikariDataSource(config) + this.dataSource = new this.HikariDataSource(config) } else { this.dataSource = dbConfig.url } } private initialize() { - this.jdbcTemplate = new JdbcTemplate(this.dataSource) + this.jdbcTemplate = new this.JdbcTemplate(this.dataSource) } /** diff --git a/packages/database/src/index.ts b/packages/database/src/index.ts index 15ab583a..11b8dc93 100644 --- a/packages/database/src/index.ts +++ b/packages/database/src/index.ts @@ -2,5 +2,11 @@ /// /// +import { loadMavenDepend } from '@ccms/container' + +loadMavenDepend('com.h2database', 'h2', '2.1.212') +loadMavenDepend("com.zaxxer", "HikariCP", "4.0.3") +loadMavenDepend("org.springframework", "spring-jdbc", "5.3.19", true) + export * from './database' -export * from './manager' \ No newline at end of file +export * from './manager' diff --git a/packages/database/src/manager.ts b/packages/database/src/manager.ts index 99037113..abc1c146 100644 --- a/packages/database/src/manager.ts +++ b/packages/database/src/manager.ts @@ -1,25 +1,18 @@ -import { plugin, database } from '@ccms/api' -import { provideSingleton, inject, postConstruct } from '@ccms/container' +import { database } from '@ccms/api' +import { provideSingleton } from '@ccms/container' import { DataBase, DataBaseConfig } from './database' @provideSingleton(database.DataBaseManager) export class DataBaseManager { - @inject(plugin.PluginInstance) - private instance: any - - private beanFactory: any private mainDatabase: DataBase - private databases: { [key: string]: DataBase } = {} + private databases = new Map() - @postConstruct() - initialize() { - try { - this.beanFactory = this.instance.getAutowireCapableBeanFactory() - let mainDatasource = this.beanFactory.getBean(Packages.javax.sql.DataSource.class) - this.mainDatabase = new DataBase({ url: mainDatasource }) - } catch (error: any) { - console.ex(error) - } + /** + * 设置主数据库 + * @param mainDatabase 主数据库 + */ + setMainDatabase(mainDatabase: DataBase) { + this.mainDatabase = mainDatabase } /** @@ -38,16 +31,19 @@ export class DataBaseManager { */ createDatabase(name: string, config: DataBaseConfig) { Java.synchronized(() => { - if (this.databases[name]) return this.databases[name] - return this.databases[name] = new DataBase(config) + if (!this.databases.has(name)) { + this.databases.set(name, new DataBase(config)) + } + return this.databases.get(name) }, this.databases)() } getDatabase(name: string) { - return this.databases[name] + return this.databases.get(name) } disable() { - Object.values(this.databases).forEach((ds) => ds?.close()) + this.databases.forEach((db) => db.close()) + this.databases.clear() } } diff --git a/packages/nashorn/src/index.ts b/packages/nashorn/src/index.ts index f5891357..da5634fe 100644 --- a/packages/nashorn/src/index.ts +++ b/packages/nashorn/src/index.ts @@ -49,7 +49,18 @@ declare global { logger: any debug: boolean level: string + /** + * 引擎配置 + */ + ScriptEngineConfig: any + /** + * 引擎版本 + */ ScriptEngineVersion: string + /** + * 引擎渠道 + */ + ScriptEngineChannel: string ScriptSlowExecuteTime: number ScriptEngineStartTime: number setGlobal: (key: string, value: any, config?: PropertyDescriptor & ThisType) => void @@ -71,6 +82,7 @@ declare global { getProxyClass(): any getJavaScriptTaskClass(): any getInstance(): any + loadMavenDepend(groupId: string, artifactId: string, version: string): [any, any] read(path: string): string save(path: string, content: string): void delete(path: string): void diff --git a/packages/plugin/src/command.ts b/packages/plugin/src/command.ts index e2cd3b23..1b75df3a 100644 --- a/packages/plugin/src/command.ts +++ b/packages/plugin/src/command.ts @@ -56,7 +56,7 @@ export class PluginCommandManager { let cmdKey = 'cmd' + subcommand if (!cmdSubCache.includes(subcommand)) { if (!pluginInstance[cmd.executor].apply(pluginInstance, [sender, command, args])) { - subcommand && pluginInstance.logger.sender(sender, '§4未知的子命令: §c' + subcommand) + subcommand && pluginInstance.logger.sender(sender, `§4未知的命令: §b/${command} §c${subcommand}`) pluginInstance.logger.sender( sender, pluginInstance['cmdhelp'] ? diff --git a/packages/plugin/src/index.ts b/packages/plugin/src/index.ts index 4642b024..8b98ca6a 100644 --- a/packages/plugin/src/index.ts +++ b/packages/plugin/src/index.ts @@ -17,3 +17,5 @@ export { config as Config, playerdata as PlayerData } from './decorators' + +import '@ccms/database'