feat: complate database & web

Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
MiaoWoo 2020-06-20 16:39:03 +08:00
parent 4c0a77ed23
commit 9b5a303c21
15 changed files with 201 additions and 56 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@ccms/database", "name": "@ccms/database",
"version": "0.6.7", "version": "0.7.0",
"description": "MiaoScript database package", "description": "MiaoScript database package",
"keywords": [ "keywords": [
"miaoscript", "miaoscript",

View File

@ -0,0 +1,3 @@
export const METADATA_KEY = {
}

View File

@ -1,9 +1,33 @@
/// <reference types="@ccms/types/dist/typings/spring" /> /// <reference types="@ccms/types/dist/typings/spring" />
import { Model } from './model'
const HikariDataSource = Java.type('com.zaxxer.hikari.HikariDataSource') const HikariDataSource = Java.type('com.zaxxer.hikari.HikariDataSource')
const HikariConfig = Java.type('com.zaxxer.hikari.HikariConfig') const HikariConfig = Java.type('com.zaxxer.hikari.HikariConfig')
const JdbcTemplate = Java.type('org.springframework.jdbc.core.JdbcTemplate') const JdbcTemplate = Java.type('org.springframework.jdbc.core.JdbcTemplate')
/**
*
*/
export interface DataBaseConfig {
/**
*
*/
url: string | javax.sql.DataSource
/**
*
*/
driverClassName?: string
/**
*
*/
username?: string
/**
*
*/
password?: string
}
/** /**
* *
*/ */
@ -11,24 +35,27 @@ 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
constructor(url: string | javax.sql.DataSource, username?: string, password?: string) { constructor(dbConfig: DataBaseConfig) {
if (!url) { throw new Error('DataBase url can\'t be null!') } if (!dbConfig.url) { throw new Error('DataBase url can\'t be null!') }
this.createDataSource(url, username, password) this.createDataSource(dbConfig)
this.initialize() this.initialize()
} }
private createDataSource(url: string | javax.sql.DataSource, username?: string, password?: string) { private createDataSource(dbConfig: DataBaseConfig) {
if (typeof url === "string") { if (typeof dbConfig.url === "string") {
if (!username || !password) { if (!dbConfig.username || !dbConfig.password) {
throw new Error('DataBase username or password can\'t be null!') throw new Error('DataBase username or password can\'t be null!')
} }
let config = new HikariConfig() let config = new HikariConfig()
config.setUsername(username) if (dbConfig.driverClassName) {
config.setPassword(password) config.setDriverClassName(dbConfig.driverClassName)
config.setJdbcUrl(url) }
config.setUsername(dbConfig.username)
config.setPassword(dbConfig.password)
config.setJdbcUrl(dbConfig.url)
this.dataSource = new HikariDataSource(config) this.dataSource = new HikariDataSource(config)
} else { } else {
this.dataSource = url this.dataSource = dbConfig.url
} }
} }
@ -41,7 +68,21 @@ export class DataBase {
* @param sql SQL语句 * @param sql SQL语句
*/ */
query<T>(sql: string, ...args: any[]): Array<T> { query<T>(sql: string, ...args: any[]): Array<T> {
return this.jdbcTemplate.queryForList(sql, args) let startTime = Date.now()
let result = Java.from(this.jdbcTemplate.queryForList(sql, args))
console.debug(java.lang.String.format(`\n[DB] query \nSQL : ${sql.replace(/\?/ig, '%s')} \nCOST : ${Date.now() - startTime}ms`, args))
return result
}
/**
* SQL更新
* @param sql SQL语句
*/
update(sql: string, ...args: any[]): number {
let startTime = Date.now()
let result = this.jdbcTemplate.update(sql, args)
console.debug(java.lang.String.format(`\n[DB] update \nSQL : ${sql.replace(/\?/ig, '%s')} \nCOST : ${Date.now() - startTime}ms`, args))
return result
} }
close() { close() {

View File

@ -0,0 +1,7 @@
import 'reflect-metadata'
export function id() {
return (target: Object, propertyKey: string | symbol) => void {
}
}

View File

@ -1,11 +1,9 @@
import { plugin, database } from '@ccms/api' import { plugin, database } from '@ccms/api'
import { provideSingleton, inject, postConstruct, Container, ContainerInstance } from '@ccms/container' import { provideSingleton, inject, postConstruct } from '@ccms/container'
import { DataBase } from './database' import { DataBase, DataBaseConfig } from './database'
@provideSingleton(database.DataBaseManager) @provideSingleton(database.DataBaseManager)
export class DataBaseManager { export class DataBaseManager {
@inject(ContainerInstance)
private container: Container
@inject(plugin.PluginInstance) @inject(plugin.PluginInstance)
private instance: any private instance: any
@ -18,20 +16,30 @@ export class DataBaseManager {
try { try {
this.beanFactory = this.instance.getAutowireCapableBeanFactory() this.beanFactory = this.instance.getAutowireCapableBeanFactory()
let mainDatasource = this.beanFactory.getBean(Packages.javax.sql.DataSource.class) let mainDatasource = this.beanFactory.getBean(Packages.javax.sql.DataSource.class)
this.mainDatabase = new DataBase(mainDatasource) this.mainDatabase = new DataBase({ url: mainDatasource })
} catch (error) { } catch (error) {
console.ex(error) console.ex(error)
} }
} }
/**
*
* Get MainDatabase
*/
getMainDatabase() { getMainDatabase() {
return this.mainDatabase return this.mainDatabase
} }
createDatabase(name: string, url: string, username: string, password: string) { /**
*
* Create A Database Instance
* @param name database Name use at code
* @param config
*/
createDatabase(name: string, config: DataBaseConfig) {
Java.synchronized(() => { Java.synchronized(() => {
if (this.databases[name]) return this.databases[name] if (this.databases[name]) return this.databases[name]
return this.databases[name] = new DataBase(url, username, password) return this.databases[name] = new DataBase(config)
}, this.databases)() }, this.databases)()
} }

View File

@ -0,0 +1,11 @@
import { DataBase } from "./database"
export class Model<T> {
constructor(private database: DataBase) {
}
queryForList(): Array<T> {
return []
}
}

View File

@ -26,6 +26,7 @@
"dependencies": { "dependencies": {
"@ccms/api": "^0.7.0", "@ccms/api": "^0.7.0",
"@ccms/common": "^0.7.0", "@ccms/common": "^0.7.0",
"@ccms/container": "^0.7.0" "@ccms/container": "^0.7.0",
"@ccms/database": "^0.7.0"
} }
} }

View File

@ -28,13 +28,16 @@ function mcColor2ANSI(str: string) {
for (const regex in regexMap) { for (const regex in regexMap) {
str = str.replace(regexMap[regex], `\u001b[${regex}m`) str = str.replace(regexMap[regex], `\u001b[${regex}m`)
} }
return str; return str
} }
export class SpringConsole extends MiaoScriptConsole { export class SpringConsole extends MiaoScriptConsole {
error(...args: any[]) { error(...args: any[]) {
this.logger.error(args.join(' ')) this.logger.error(args.join(' '))
} }
warn(...args: any[]) {
this.logger.warn(args.join(' '))
}
sender(sender: any, ...args: any[]) { sender(sender: any, ...args: any[]) {
sender = sender || { sender = sender || {
sendMessage: (message: string) => console.console(message) sendMessage: (message: string) => console.console(message)
@ -46,7 +49,7 @@ export class SpringConsole extends MiaoScriptConsole {
if (Object.prototype.toString.call(args[0]) === '[object Array]') { if (Object.prototype.toString.call(args[0]) === '[object Array]') {
args[0].forEach(line => sender.sendMessage(this.prefix + line)) args[0].forEach(line => sender.sendMessage(this.prefix + line))
} else { } else {
sender.sendMessage(this.prefix + args.join(' ')); sender.sendMessage(this.prefix + args.join(' '))
} }
} }
console(...args: string[]): void { console(...args: string[]): void {

View File

@ -1,13 +1,29 @@
import { server } from '@ccms/api' import { server } from '@ccms/api'
import { Container } from '@ccms/container' import { ioc, Container, reduceMetadata } from '@ccms/container'
import '@ccms/database'
import { SpringConsole } from './console'; import { SpringConsole } from './console'
import './event'; import './event'
import './server'; import './server'
import './command'; import './command'
import './task'; import './task'
const toString = {}.toString
export default function SpringImpl(container: Container) { export default function SpringImpl(container: Container) {
try {
require('@ccms/web')
require('@ccms/amqp')
require('@ccms/database')
require('./internal/scanner/mysql-scanner')
} catch (error) {
console.ex(error)
}
const beanFactory = base.getInstance().getAutowireCapableBeanFactory()
container.bind(server.Console).toConstantValue(SpringConsole) container.bind(server.Console).toConstantValue(SpringConsole)
container.bind(ioc.Autowired).toDynamicValue((ctx) => {
var metadata: any = reduceMetadata(ctx)
if (toString.call(metadata.named) === "[object Symbol]") { return container.get(metadata.named) }
if (toString.call(metadata.named) === '[object jdk.internal.dynalink.beans.StaticClass]') { metadata.named = metadata.named.class }
return beanFactory.getBean(metadata.named)
})
} }

View File

@ -34,12 +34,32 @@ export class CommandMap {
} }
let exists = this.commands[command] let exists = this.commands[command]
if (exists) { if (exists) {
return exists.executor(sender, '', command, Java.to(args)) try {
return exists.executor(sender, '', command, Java.to(args))
} catch (error) {
console.ex(error)
}
return true
} else { } else {
sender.sendMessage && sender.sendMessage(`Unknown command. Type "/help" for help.`) sender.sendMessage && sender.sendMessage(`Unknown command. Type "/help" for help.`)
return false return false
} }
} }
tabComplate(sender: any, input: string, index?: number): string[] {
if (index == 0) { return Object.keys(this.commands) }
let [command, ...args] = input.split(' ')
let exists = this.commands[command]
if (exists && exists.tabCompleter) {
try {
if (args.length !== index) { args.push('') }
return exists.tabCompleter(sender, '', command, Java.to(args))
} catch (error) {
console.ex(error)
}
}
return []
}
} }
export class SpringCommand { export class SpringCommand {

View File

@ -0,0 +1,32 @@
import { plugin, database } from '@ccms/api'
import { DataBaseManager } from '@ccms/database'
import { provideSingleton, inject } from '@ccms/container'
import * as fs from '@ccms/common/dist/fs'
@provideSingleton(plugin.PluginScanner)
export class MySQLScanner implements plugin.PluginScanner {
type: string = "mysql"
private target: string
@inject(database.DataBaseManager)
private databaseManager: DataBaseManager
scan(target: any): string[] {
this.target = target
let plugins = this.databaseManager.getMainDatabase().query<{ name: string }>(`SELECT name FROM ${this.target} WHERE LENGTH(source) != 0 AND deleted = 0`)
return plugins.map(p => `mysql:${p.name}`)
}
load(target: any) {
if (typeof target !== "string" || !target.startsWith('mysql:')) { return }
let name = target.split("mysql:")[1]
if (!name) { console.warn(`[PluginScanner][mysql] plugin name can't be null!`); return }
var plugin: any = this.databaseManager.getMainDatabase().query<{ source: string }>(`SELECT source FROM ${this.target} WHERE name = ? AND deleted = 0`, name)
if (plugin.length == 0) { console.warn(`[PluginScanner][mysql] plugin ${target} not found at mysql database...`); return }
let temp = fs.concat(root, 'mysql-plugin-cache', target, `${plugin[0]}.js`)
base.save(temp, plugin[0].source)
//@ts-ignore
return require(temp, { cache: false })
}
}

View File

@ -21,6 +21,7 @@ export class SpringServer implements server.Server {
} }
getConsoleSender() { getConsoleSender() {
return { return {
name: 'CONSOLE',
sendMessage: (message: string) => console.console(message) sendMessage: (message: string) => console.console(message)
} }
} }
@ -50,6 +51,6 @@ export class SpringServer implements server.Server {
throw new Error("Method not implemented.") throw new Error("Method not implemented.")
} }
tabComplete(sender: any, input: string, index?: number) { tabComplete(sender: any, input: string, index?: number) {
throw new Error("Method not implemented.") return this.commandMap.tabComplate(sender, input, index)
} }
} }

View File

@ -1,29 +1,30 @@
import { task, plugin } from '@ccms/api' import { task, plugin } from '@ccms/api'
import { inject, provideSingleton } from '@ccms/container' import { inject, provideSingleton } from '@ccms/container'
import thread_pool from '@ccms/common/dist/thread-pool'
const AtomicInteger = Java.type("java.util.concurrent.atomic.AtomicInteger")
const AtomicBoolean = Java.type("java.util.concurrent.atomic.AtomicBoolean") const AtomicBoolean = Java.type("java.util.concurrent.atomic.AtomicBoolean")
const Thread = Java.type('java.lang.Thread') const Thread = Java.type('java.lang.Thread')
const ThreadPoolExecutor = Java.type('java.util.concurrent.ThreadPoolExecutor')
const ThreadPoolTaskExecutor = Java.type('org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor')
let executor: any const taskId = new AtomicInteger(0)
let tasks: { [key: number]: task.Cancelable } = {} const tasks: { [key: number]: task.Cancelable } = {}
let taskId = 0 const executor = thread_pool.create({
groupName: '@ccms/spring'
})
@provideSingleton(task.TaskManager) @provideSingleton(task.TaskManager)
export class SpringTaskManager implements task.TaskManager { export class SpringTaskManager implements task.TaskManager {
@inject(plugin.PluginInstance) @inject(plugin.PluginInstance)
private pluginInstance: any private pluginInstance: any
private innerTaskId: any
private innerTasks: { [s: string]: task.Cancelable }
private innerExecutor: java.util.concurrent.ThreadPoolExecutor
constructor() { constructor() {
executor = new ThreadPoolTaskExecutor() this.innerTaskId = taskId
executor.setCorePoolSize(10) this.innerTasks = tasks
executor.setMaxPoolSize(100) this.innerExecutor = executor
executor.setQueueCapacity(500)
executor.setKeepAliveSeconds(60)
executor.setThreadNamePrefix("@ccms/spring-")
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy())
executor.initialize()
} }
create(func: Function): task.Task { create(func: Function): task.Task {
@ -34,13 +35,13 @@ export class SpringTaskManager implements task.TaskManager {
return func() return func()
} }
disable() { disable() {
Object.values(tasks).forEach((task) => task?.cancel()) Object.values(this.innerTasks).forEach((task) => task?.cancel())
executor.shutdown(); this.innerExecutor.shutdown()
} }
} }
export class SpringTask extends task.Task { export class SpringTask extends task.Task {
public id = taskId++ public id = taskId.incrementAndGet()
private running = new AtomicBoolean(true) private running = new AtomicBoolean(true)
run(...args: any[]) { run(...args: any[]) {
@ -78,7 +79,7 @@ export class SpringTask extends task.Task {
submit(...args: any[]): task.Cancelable { submit(...args: any[]): task.Cancelable {
tasks[this.id] = this tasks[this.id] = this
executor.execute(() => this.run(...args)) executor.execute((() => this.run(...args)) as any)
return { return {
cancel: () => { cancel: () => {
return this.cancel() return this.cancel()

View File

@ -3,11 +3,6 @@ export const Controller = () => {
return return
} }
} }
export const Header = () => {
return <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>): MethodDecorator => {
return
}
}
export const Post = () => { export const Post = () => {
return <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>): MethodDecorator => { return <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>): MethodDecorator => {
return return
@ -18,6 +13,11 @@ export const Get = () => {
return return
} }
} }
export const Header = () => {
return <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>): MethodDecorator => {
return
}
}
export const Param = () => { export const Param = () => {
return (target: Object, propertyKey: string | symbol, parameterIndex: number): ParameterDecorator => { return (target: Object, propertyKey: string | symbol, parameterIndex: number): ParameterDecorator => {
return return

View File

@ -156,9 +156,10 @@ export class Server {
} }
console.debug(` console.debug(`
===================== MiaoSpring ===================== ===================== MiaoSpring =====================
Request URL : ${ctx.url} Request Method : ${ctx.request.getMethod()}
Response Body : ${JSON.stringify(Java.asJSONCompatible(ctx.result))} Request URL : ${ctx.url}
Handle Time : ${Date.now() - startTime}ms Response Body : ${JSON.stringify(Java.asJSONCompatible(ctx.result))}
Handle Time : ${Date.now() - startTime}ms
======================================================`) ======================================================`)
return ctx.result return ctx.result
} }