feat: add loadMavenDepend & optimize database
Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
		@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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) { }
 | 
			
		||||
        _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<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 => {
 | 
			
		||||
    return ctx.currentRequest.target.metadata.reduce((result, entry, index) => {
 | 
			
		||||
        result[entry.key] = entry.value
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								packages/container/src/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								packages/container/src/utils.ts
									
									
									
									
									
										Normal 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
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
@@ -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')
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
            }
 | 
			
		||||
            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)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -2,5 +2,11 @@
 | 
			
		||||
/// <reference types="@javatypes/jdk" />
 | 
			
		||||
/// <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 './manager'
 | 
			
		||||
@@ -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<string, DataBase>()
 | 
			
		||||
 | 
			
		||||
    @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()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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<any>) => 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
 | 
			
		||||
 
 | 
			
		||||
@@ -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'] ?
 | 
			
		||||
 
 | 
			
		||||
@@ -17,3 +17,5 @@ export {
 | 
			
		||||
    config as Config,
 | 
			
		||||
    playerdata as PlayerData
 | 
			
		||||
} from './decorators'
 | 
			
		||||
 | 
			
		||||
import '@ccms/database'
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user