feat: add loadMavenDepend & optimize database

Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
MiaoWoo 2022-04-25 00:41:11 +08:00
parent 579d89ae89
commit 8d0484eefb
10 changed files with 165 additions and 68 deletions

View File

@ -1,38 +1,9 @@
import { interfaces, Container } from "inversify" import { interfaces, Container } from "inversify"
import { _proxyGetter } from "./utils"
let _container: Container let _container: Container
const ContainerInstance = Symbol.for("@ccms/ioc: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) { function initContainer(container: Container) {
Reflect.defineMetadata(ContainerInstance, container, Reflect) Reflect.defineMetadata(ContainerInstance, container, Reflect)

View File

@ -5,6 +5,7 @@ import { initContainer, getContainer } from './decorators'
import { interfaces, Container, inject, named } from 'inversify' import { interfaces, Container, inject, named } from 'inversify'
import { fluentProvide } from 'inversify-binding-decorators' import { fluentProvide } from 'inversify-binding-decorators'
import { ioc } from "./constants" import { ioc } from "./constants"
import { _proxyGetter } from "./utils"
/** /**
* *
@ -49,9 +50,11 @@ export const JavaClass = (className: string) => {
*/ */
export const JSClass = (className: string) => { export const JSClass = (className: string) => {
return function (target: object, propertyKey: string, index?: number) { return function (target: object, propertyKey: string, index?: number) {
try { target[propertyKey] = Java.type(className); return } catch (error: any) { } _proxyGetter(target, propertyKey, () => {
try { target[propertyKey] = base.getClass(className).static; return } catch (error: any) { } 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!') 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<string>()
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 => { export const reduceMetadata = (ctx: interfaces.Context): any => {
return ctx.currentRequest.target.metadata.reduce((result, entry, index) => { return ctx.currentRequest.target.metadata.reduce((result, entry, index) => {
result[entry.key] = entry.value result[entry.key] = entry.value

View File

@ -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
})
}

View File

@ -3,7 +3,11 @@ console.i18n("ms.core.ioc.initialize", { scope: global.scope })
import { plugin, server, task, constants } from '@ccms/api' import { plugin, server, task, constants } from '@ccms/api'
import { DefaultContainer as container, provideSingleton, ContainerInstance, buildProviderModule, Autowired } from '@ccms/container' 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 }) 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 http from '@ccms/common/dist/http'
import * as fs from '@ccms/common/dist/fs'
const UUID = Java.type('java.util.UUID')
@provideSingleton(MiaoScriptCore) @provideSingleton(MiaoScriptCore)
class 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() { function initialize() {
process.emit('core.before.initialize') process.emit('core.before.initialize')
global.ScriptSlowExecuteTime = 50 loadMiaoScriptConfig()
global.ScriptEngineVersion = require('../package.json').version global.ScriptEngineVersion = require('../package.json').version
global.setGlobal('loadCoreScript', loadCoreScript) global.setGlobal('loadCoreScript', loadCoreScript)
loadCoreScript('initialize') loadCoreScript('initialize')

View File

@ -1,9 +1,6 @@
import { JSClass } from '@ccms/container'
import { Model } from './model' 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 dataSource: javax.sql.DataSource
private jdbcTemplate: org.springframework.jdbc.core.JdbcTemplate 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) { constructor(dbConfig: DataBaseConfig) {
if (!dbConfig.url) { throw new Error('DataBase url can\'t be null!') } if (!dbConfig.url) { throw new Error('DataBase url can\'t be null!') }
this.createDataSource(dbConfig) this.createDataSource(dbConfig)
@ -41,24 +45,25 @@ export class DataBase {
private createDataSource(dbConfig: DataBaseConfig) { private createDataSource(dbConfig: DataBaseConfig) {
if (typeof dbConfig.url === "string") { if (typeof dbConfig.url === "string") {
if (!dbConfig.username || !dbConfig.password) { let config = new this.HikariConfig()
throw new Error('DataBase username or password can\'t be null!')
}
let config = new HikariConfig()
if (dbConfig.driverClassName) { if (dbConfig.driverClassName) {
config.setDriverClassName(dbConfig.driverClassName) config.setDriverClassName(dbConfig.driverClassName)
} }
if (dbConfig.username) {
config.setUsername(dbConfig.username) config.setUsername(dbConfig.username)
}
if (dbConfig.password) {
config.setPassword(dbConfig.password) config.setPassword(dbConfig.password)
}
config.setJdbcUrl(dbConfig.url) config.setJdbcUrl(dbConfig.url)
this.dataSource = new HikariDataSource(config) this.dataSource = new this.HikariDataSource(config)
} else { } else {
this.dataSource = dbConfig.url this.dataSource = dbConfig.url
} }
} }
private initialize() { private initialize() {
this.jdbcTemplate = new JdbcTemplate(this.dataSource) this.jdbcTemplate = new this.JdbcTemplate(this.dataSource)
} }
/** /**

View File

@ -2,5 +2,11 @@
/// <reference types="@javatypes/jdk" /> /// <reference types="@javatypes/jdk" />
/// <reference types="@javatypes/spring-jdbc" /> /// <reference types="@javatypes/spring-jdbc" />
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 './database'
export * from './manager' export * from './manager'

View File

@ -1,25 +1,18 @@
import { plugin, database } from '@ccms/api' import { database } from '@ccms/api'
import { provideSingleton, inject, postConstruct } from '@ccms/container' import { provideSingleton } from '@ccms/container'
import { DataBase, DataBaseConfig } from './database' import { DataBase, DataBaseConfig } from './database'
@provideSingleton(database.DataBaseManager) @provideSingleton(database.DataBaseManager)
export class DataBaseManager { export class DataBaseManager {
@inject(plugin.PluginInstance)
private instance: any
private beanFactory: any
private mainDatabase: DataBase private mainDatabase: DataBase
private databases: { [key: string]: DataBase } = {} private databases = new Map<string, DataBase>()
@postConstruct() /**
initialize() { *
try { * @param mainDatabase
this.beanFactory = this.instance.getAutowireCapableBeanFactory() */
let mainDatasource = this.beanFactory.getBean(Packages.javax.sql.DataSource.class) setMainDatabase(mainDatabase: DataBase) {
this.mainDatabase = new DataBase({ url: mainDatasource }) this.mainDatabase = mainDatabase
} catch (error: any) {
console.ex(error)
}
} }
/** /**
@ -38,16 +31,19 @@ export class DataBaseManager {
*/ */
createDatabase(name: string, config: DataBaseConfig) { createDatabase(name: string, config: DataBaseConfig) {
Java.synchronized(() => { Java.synchronized(() => {
if (this.databases[name]) return this.databases[name] if (!this.databases.has(name)) {
return this.databases[name] = new DataBase(config) this.databases.set(name, new DataBase(config))
}
return this.databases.get(name)
}, this.databases)() }, this.databases)()
} }
getDatabase(name: string) { getDatabase(name: string) {
return this.databases[name] return this.databases.get(name)
} }
disable() { disable() {
Object.values(this.databases).forEach((ds) => ds?.close()) this.databases.forEach((db) => db.close())
this.databases.clear()
} }
} }

View File

@ -49,7 +49,18 @@ declare global {
logger: any logger: any
debug: boolean debug: boolean
level: string level: string
/**
*
*/
ScriptEngineConfig: any
/**
*
*/
ScriptEngineVersion: string ScriptEngineVersion: string
/**
*
*/
ScriptEngineChannel: string
ScriptSlowExecuteTime: number ScriptSlowExecuteTime: number
ScriptEngineStartTime: number ScriptEngineStartTime: number
setGlobal: (key: string, value: any, config?: PropertyDescriptor & ThisType<any>) => void setGlobal: (key: string, value: any, config?: PropertyDescriptor & ThisType<any>) => void
@ -71,6 +82,7 @@ declare global {
getProxyClass(): any getProxyClass(): any
getJavaScriptTaskClass(): any getJavaScriptTaskClass(): any
getInstance(): any getInstance(): any
loadMavenDepend(groupId: string, artifactId: string, version: string): [any, any]
read(path: string): string read(path: string): string
save(path: string, content: string): void save(path: string, content: string): void
delete(path: string): void delete(path: string): void

View File

@ -56,7 +56,7 @@ export class PluginCommandManager {
let cmdKey = 'cmd' + subcommand let cmdKey = 'cmd' + subcommand
if (!cmdSubCache.includes(subcommand)) { if (!cmdSubCache.includes(subcommand)) {
if (!pluginInstance[cmd.executor].apply(pluginInstance, [sender, command, args])) { 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( pluginInstance.logger.sender(
sender, sender,
pluginInstance['cmdhelp'] ? pluginInstance['cmdhelp'] ?

View File

@ -17,3 +17,5 @@ export {
config as Config, config as Config,
playerdata as PlayerData playerdata as PlayerData
} from './decorators' } from './decorators'
import '@ccms/database'