diff --git a/packages/api/src/interfaces/amqp.ts b/packages/api/src/amqp.ts
similarity index 100%
rename from packages/api/src/interfaces/amqp.ts
rename to packages/api/src/amqp.ts
diff --git a/packages/api/src/command.ts b/packages/api/src/command.ts
index 5e652d6b..cb4ef843 100644
--- a/packages/api/src/command.ts
+++ b/packages/api/src/command.ts
@@ -1,6 +1,6 @@
import i18n from '@ccms/i18n'
import { injectable } from "@ccms/container"
-import { plugin } from './interfaces'
+import { plugin } from './plugin'
export namespace command {
@injectable()
diff --git a/packages/api/src/constants.ts b/packages/api/src/constants.ts
index a210564d..172eaac0 100644
--- a/packages/api/src/constants.ts
+++ b/packages/api/src/constants.ts
@@ -1,4 +1,14 @@
export namespace constants {
+ export namespace ServiceIdentifier {
+ /**
+ * Runtime Server NettyPipeline
+ */
+ export const NettyPipeline = Symbol("NettyPipeline")
+ /**
+ * Runtime Server RootLogger
+ */
+ export const RootLogger = Symbol("RootLogger")
+ }
export namespace Reflect {
export const Method = {
getServerConnection: [/*spigot 1.8.8*/'aq',/*spigot 1.12.2*/ 'an', /*spigot 1.14.4+*/'getServerConnection', /*catserver 1.12.2*/'func_147137_ag']
diff --git a/packages/api/src/interfaces/database.ts b/packages/api/src/database.ts
similarity index 100%
rename from packages/api/src/interfaces/database.ts
rename to packages/api/src/database.ts
diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts
index 01b84754..4a0b3035 100644
--- a/packages/api/src/index.ts
+++ b/packages/api/src/index.ts
@@ -1,11 +1,15 @@
import "@ccms/nashorn"
+export * from './web'
+export * from './amqp'
export * from './chat'
export * from './task'
export * from './event'
export * from './proxy'
+export * from './plugin'
+export * from './server'
export * from './console'
export * from './channel'
export * from './command'
+export * from './database'
export * from './constants'
-export * from './interfaces'
diff --git a/packages/api/src/interfaces/index.ts b/packages/api/src/interfaces/index.ts
deleted file mode 100644
index 24fb9409..00000000
--- a/packages/api/src/interfaces/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export * from './web'
-export * from './amqp'
-export * from './plugin'
-export * from './server'
-export * from './database'
diff --git a/packages/api/src/interfaces/server/native_plugin.ts b/packages/api/src/interfaces/server/native_plugin.ts
deleted file mode 100644
index 3edb6498..00000000
--- a/packages/api/src/interfaces/server/native_plugin.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export interface NativePluginManager {
- load(name: string): boolean;
- unload(name: string): boolean;
- reload(name: string): boolean;
- delete(name: string): boolean;
-}
\ No newline at end of file
diff --git a/packages/api/src/interfaces/plugin.ts b/packages/api/src/plugin.ts
similarity index 96%
rename from packages/api/src/interfaces/plugin.ts
rename to packages/api/src/plugin.ts
index fcce919c..d45457c0 100644
--- a/packages/api/src/interfaces/plugin.ts
+++ b/packages/api/src/plugin.ts
@@ -78,7 +78,7 @@ export namespace plugin {
scan(target: any): PluginLoadMetadata[]
/**
* 读取插件 返回插件加载元信息
- * @param target
+ * @param target
*/
read(target: any): PluginLoadMetadata
/**
@@ -162,6 +162,14 @@ export namespace plugin {
* 插件作者 不填默认为 Unknow
*/
author?: string | string[]
+ /**
+ * 脚本依赖
+ */
+ depends?: string[]
+ /**
+ * 插件依赖
+ */
+ nativeDepends?: string[]
/**
* 插件源文件 必须指定为 __filename
*/
diff --git a/packages/api/src/interfaces/server/index.ts b/packages/api/src/server.ts
similarity index 74%
rename from packages/api/src/interfaces/server/index.ts
rename to packages/api/src/server.ts
index df972ca1..c721b7cb 100644
--- a/packages/api/src/interfaces/server/index.ts
+++ b/packages/api/src/server.ts
@@ -1,10 +1,7 @@
import * as reflect from '@ccms/common/dist/reflect'
-import { injectable, inject } from '@ccms/container'
+import { injectable, Autowired, ContainerInstance, Container, postConstruct } from '@ccms/container'
-import { NativePluginManager } from './native_plugin'
-import { constants } from '../../constants'
-
-export { NativePluginManager } from './native_plugin'
+import { constants } from './constants'
export namespace server {
/**
@@ -19,6 +16,24 @@ export namespace server {
* Runtime Server Instance
*/
export const ServerInstance = Symbol("ServerInstance")
+ @injectable()
+ export abstract class NativePluginManager {
+ has(name: string): boolean {
+ return true
+ }
+ load(name: string): boolean {
+ throw new Error("Method not implemented.")
+ }
+ unload(name: string): boolean {
+ throw new Error("Method not implemented.")
+ }
+ reload(name: string): boolean {
+ throw new Error("Method not implemented.")
+ }
+ delete(name: string): boolean {
+ throw new Error("Method not implemented.")
+ }
+ }
/**
* MiaoScript Server
*/
@@ -48,9 +63,6 @@ export namespace server {
getPluginsFolder(): string {
throw new Error("Method not implemented.")
}
- getNativePluginManager(): NativePluginManager {
- throw new Error("Method not implemented.")
- }
getDedicatedServer?(): any {
throw new Error("Method not implemented.")
}
@@ -63,8 +75,9 @@ export namespace server {
}
@injectable()
export class ServerChecker {
- @inject(ServerType)
+ @Autowired(ServerType)
private serverType: string
+
check(servers: string[]) {
// Not set servers -> allow
if (!servers || !servers.length) return true
@@ -80,14 +93,17 @@ export namespace server {
}
@injectable()
export abstract class ReflectServer extends server.Server {
+ @Autowired(ContainerInstance)
+ private container: Container
+
protected pipeline: any
protected rootLogger: any
constructor() {
super()
- this.reflect()
}
+ @postConstruct()
protected reflect() {
try {
let consoleServer = this.getDedicatedServer()
@@ -107,7 +123,11 @@ export namespace server {
if (connection.class.name.indexOf('ServerConnection') !== -1
|| connection.class.name.indexOf('NetworkSystem') !== -1) { break }
connection = undefined
- } catch (error) { }
+ } catch (error) {
+ if (global.debug) {
+ console.ex(error)
+ }
+ }
}
if (!connection) { console.error("Can't found ServerConnection!"); return }
for (const field of constants.Reflect.Field.listeningChannels) {
@@ -115,16 +135,30 @@ export namespace server {
promise = reflect.on(connection).get(field).get().get(0)
if (promise.class.name.indexOf('Promise') !== -1) { break }
promise = undefined
- } catch (error) { }
+ } catch (error) {
+ if (global.debug) {
+ console.ex(error)
+ }
+ }
}
if (!promise) { console.error("Can't found listeningChannels!"); return }
this.pipeline = reflect.on(promise).get('channel').get().pipeline()
+ this.container.bind(constants.ServiceIdentifier.NettyPipeline).toConstantValue(this.pipeline)
}
protected reflectRootLogger(consoleServer: any) {
try {
this.rootLogger = reflect.on(consoleServer).get('LOGGER').get().parent
} catch (error) {
- try { this.rootLogger = reflect.on(consoleServer).get(0).get().parent } catch (error) { }
+ if (global.debug) {
+ console.ex(error)
+ }
+ try {
+ this.rootLogger = reflect.on(consoleServer).get(0).get().parent
+ } catch (error) {
+ if (global.debug) {
+ console.ex(error)
+ }
+ }
}
if (this.rootLogger && this.rootLogger.class.name.indexOf('Logger') === -1) {
console.error('Error Logger Class: ' + this.rootLogger.class.name)
@@ -135,6 +169,7 @@ export namespace server {
this.rootLogger = this.rootLogger.parent
}
if (!this.rootLogger) { console.error("Can't found rootLogger!") }
+ this.container.bind(constants.ServiceIdentifier.RootLogger).toConstantValue(this.rootLogger)
}
}
}
diff --git a/packages/api/src/interfaces/web.ts b/packages/api/src/web.ts
similarity index 100%
rename from packages/api/src/interfaces/web.ts
rename to packages/api/src/web.ts
diff --git a/packages/common/src/reflect.ts b/packages/common/src/reflect.ts
index 8e2e4c6e..278d5da7 100644
--- a/packages/common/src/reflect.ts
+++ b/packages/common/src/reflect.ts
@@ -1,14 +1,15 @@
///
+const JavaClass = Java.type('java.lang.Class')
+const JavaObject = Java.type('java.lang.Object')
+const NoSuchFieldException = Java.type('java.lang.NoSuchFieldException')
+const fieldCache = new Map()
+const methodCache = new Map()
+
/**
* 反射工具类
* Created by MiaoWoo on 2017/2/9 0009.
*/
-const JavaClass = Java.type('java.lang.Class')
-const JavaObject = Java.type('java.lang.Object')
-const NoSuchFieldException = Java.type('java.lang.NoSuchFieldException')
-const methodCache = []
-
class Reflect {
private obj: java.lang.Object
private class: java.lang.Class
@@ -34,15 +35,26 @@ class Reflect {
return Java.from(declaredMethods(this.class))
}
- field(name: string | java.lang.String): Reflect {
- try {
- // Try getting a public field
- let field = this.class.getField(name)
- return on(field.get(this.obj))
- } catch (ex) {
- // Try again, getting a non-public field
- return on(accessible(declaredField(this.class, name)).get(this.obj))
+ field(nameOrIndex: string | java.lang.String | number, declared = false): java.lang.reflect.Field {
+ if (nameOrIndex == undefined || nameOrIndex == null) throw new Error(`reflect field name can't be ${nameOrIndex} from ${this.class.getName()}!`)
+ let key = this.class.getName() + ':' + nameOrIndex + ':' + declared
+ if (fieldCache.has(key)) {
+ return fieldCache.get(key)
}
+ let field = null
+ if (typeof nameOrIndex == "number") {
+ field = this.fields(declared)[nameOrIndex]
+ } else {
+ try {
+ // Try getting a public field
+ field = this.class.getField(nameOrIndex)
+ } catch (ex) {
+ // Try again, getting a non-public field
+ field = declaredField(this.class, nameOrIndex)
+ }
+ }
+ if (!field) throw new Error(`can't reflect field ${typeof nameOrIndex == "number" ? 'index' : 'name'} ${nameOrIndex} from ${this.class.getName()}!`)
+ return accessible(field)
}
fields(declared = false): java.lang.reflect.Field[] {
@@ -50,7 +62,7 @@ class Reflect {
}
values(declared = false) {
- return this.fields(declared).reduce((cache, field) => { return cache[field.getName()] = this.field(field.getName()).get() }, {}) as any
+ return this.fields(declared).reduce((cache, field) => { return cache[field.getName()] = this.get(field.getName()).get() }, {}) as any
}
call(...args: any[]): Reflect {
@@ -64,17 +76,12 @@ class Reflect {
get(index: number, declared?: boolean): Reflect
get(prop: string): Reflect
get(param?: string | number, declared: boolean = true): Reflect | any {
- if (param == undefined || param == null) return this.obj
- if (typeof param == "number") {
- return on(accessible(this.fields(declared)[param]).get(this.obj))
- }
- if (typeof param == "string") {
- return this.field(param)
- }
+ if (arguments.length === 0) return this.obj
+ return on(this.field(param, declared).get(this.obj))
}
- set(name: any, value: any): Reflect {
- accessible(declaredField(this.class, name)).set(this.obj, value)
+ set(param: string | number, value: any, declared: boolean = true): Reflect {
+ this.field(param, declared).set(this.obj, value)
return this
}
@@ -136,64 +143,43 @@ function declaredField(clazz: java.lang.Class, name: string | java.lang.Str
return field
}
-function declaredMethod(clazz: java.lang.Class, name: string, ...clazzs: java.lang.Class[]): java.lang.reflect.Method {
- let key = clazz.getName() + '.' + name + ':' + (clazzs || []).join(':')
- if (!methodCache[key]) {
+function declaredMethod(clazz: java.lang.Class, nameOrIndex: string | number, ...clazzs: java.lang.Class[]): java.lang.reflect.Method {
+ let key = clazz.getName() + '.' + nameOrIndex + ':' + (clazzs || []).map(c => c.getName()).join(':')
+ if (methodCache.has(key)) { return methodCache.get(key) }
+ if (typeof nameOrIndex === "number") {
+ methodCache.set(key, declaredMethods(clazz)[nameOrIndex])
+ } else {
try {
- // @ts-ignore
- methodCache[key] = clazz.getMethod(name, clazzs)
+ methodCache.set(key, clazz.getMethod(nameOrIndex, clazzs as any))
} catch (ex) {
try {
- methodCache[key] = clazz.getDeclaredMethod(name, clazzs as any)
+ methodCache.set(key, clazz.getDeclaredMethod(nameOrIndex, clazzs as any))
} catch (ex) {
for (const m of Java.from(declaredMethods(clazz))) {
- if (m.getName() == name) {
- methodCache[key] = m
+ if (m.getName() == nameOrIndex) {
+ methodCache.set(key, m)
break
}
}
}
}
}
- return methodCache[key]
+ if (!methodCache.has(key)) throw new Error(`can't reflect method ${typeof nameOrIndex == "number" ? 'index' : 'name'} ${nameOrIndex} from ${clazz.getName()}!`)
+ return methodCache.get(key)
}
function declaredMethods(clazz: java.lang.Class) {
return clazz.getDeclaredMethods()
}
-let classMethodsCache: any[] = []
-
function mapToObject(javaObj) {
- if (!javaObj || !javaObj.class) { throw new TypeError(`参数 ${javaObj} 不是一个Java对象!`) }
- let target = {}
- getJavaObjectMethods(javaObj).forEach(t => mapMethod(target, javaObj, t))
+ if (!Java.isJavaObject(javaObj)) { throw new TypeError(`参数 ${javaObj} 不是一个Java对象!`) }
+ let target = Proxy.newProxy(javaObj, {
+ apply: (target, name, args) => { return args ? javaObj[name](args) : javaObj[name]() }
+ })
return target
}
-function getJavaObjectMethods(javaObj) {
- let className = javaObj.class.name
- if (!classMethodsCache[className]) {
- let names: any[] = []
- let methods = javaObj.class.methods
- for (let i in methods) {
- names.push(methods[i].name)
- }
- classMethodsCache[className] = names
- }
- return classMethodsCache[className]
-}
-
-function mapMethod(target, source, name) {
- target[name] = function __SimpleDynamicMethod__(...args) {
- if (args.length > 0) {
- return source[name](args)
- } else {
- return source[name]()
- }
- }
-}
-
function on(obj) {
// if (!obj || !obj.class) { throw new TypeError(`参数 ${obj} 不是一个Java对象!`) }
return new Reflect(obj)
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index e0ba363a..7f7cc27f 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -99,6 +99,7 @@ function initialize() {
console.i18n("ms.core.initialize.detect", { scope: global.scope, type })
container.bind(server.ServerType).toConstantValue(type)
container.bind(server.ServerChecker).toSelf().inSingletonScope()
+ container.bind(server.NativePluginManager).toSelf().inSingletonScope()
console.i18n("ms.core.package.initialize", { scope: global.scope, type })
require(`${global.scope}/${type}`).default(container)
require(`${global.scope}/plugin`)
diff --git a/packages/nashorn/src/index.ts b/packages/nashorn/src/index.ts
index cb5d4692..5c9ccfa7 100644
--- a/packages/nashorn/src/index.ts
+++ b/packages/nashorn/src/index.ts
@@ -81,8 +81,18 @@ declare global {
i18n(name: string, ...params: any[]): void
}
interface ProxyConstructor {
- newProxy(target: T, handler: ProxyHandler): T
+ newProxy(target: T, handler: ProxyHandle): T
}
}
-
+export interface ProxyHandle extends ProxyHandler {
+ setPrototypeOf?(target: T, v: any): any
+ // get: (target: any, name: string) => any
+ // set: (target: any, name: string, value: any) => boolean
+ // construct: (target: any, ...args: any[]) => any
+ // has: (target: any, name: string) => boolean
+ // ownKeys: (target: any) => string[]
+ values?: (target: T) => any[]
+ // call: (target: any, name: string, ...args: any[]) => any
+ // deleteProperty: (target: any, name: string) => boolean
+}
export { }
diff --git a/packages/ployfill/src/proxy.ts b/packages/ployfill/src/proxy.ts
index f7eb7558..32b99f44 100644
--- a/packages/ployfill/src/proxy.ts
+++ b/packages/ployfill/src/proxy.ts
@@ -1,17 +1,9 @@
+import { ProxyHandle } from '@ccms/nashorn'
+
// Nashorn JSAdapter See https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-JSAdapterconstructor
let createProxy = eval(`
function(handle){ return new JSAdapter(handle) }
`)
-export interface ProxyHandle extends ProxyHandler {
- // get: (target: any, name: string) => any
- // set: (target: any, name: string, value: any) => boolean
- // construct: (target: any, ...args: any[]) => any
- // has: (target: any, name: string) => boolean
- // ownKeys: (target: any) => string[]
- values: (target: any) => any[];
- // call: (target: any, name: string, ...args: any[]) => any
- // deleteProperty: (target: any, name: string) => boolean
-}
export class Proxy {
static newProxy(target: any, handle: Partial): any {
return new Proxy(target, handle)
diff --git a/packages/plugin/src/manager.ts b/packages/plugin/src/manager.ts
index e4faa9c7..000409bf 100644
--- a/packages/plugin/src/manager.ts
+++ b/packages/plugin/src/manager.ts
@@ -1,6 +1,6 @@
import i18n from '@ccms/i18n'
-import { plugin, server, event } from '@ccms/api'
-import { inject, provideSingleton, Container, ContainerInstance, Autowired } from '@ccms/container'
+import { plugin, server } from '@ccms/api'
+import { provideSingleton, Container, ContainerInstance, Autowired } from '@ccms/container'
import './config'
import { interfaces } from './interfaces'
@@ -13,15 +13,17 @@ const Thread = Java.type('java.lang.Thread')
@provideSingleton(plugin.PluginManager)
export class PluginManagerImpl implements plugin.PluginManager {
- @inject(ContainerInstance)
+ @Autowired(ContainerInstance)
private container: Container
- @inject(plugin.PluginInstance)
+ @Autowired(plugin.PluginInstance)
private pluginInstance: any
- @inject(server.ServerType)
+ @Autowired(server.ServerType)
private serverType: string
@Autowired()
private serverChecker: server.ServerChecker
+ @Autowired()
+ private nativePluginManager: server.NativePluginManager
@Autowired()
private taskManager: PluginTaskManager
@@ -224,15 +226,28 @@ export class PluginManagerImpl implements plugin.PluginManager {
try {
this.buildPlugin(metadata)
} catch (error) {
- console.console(error)
+ console.console(`§4无法加载插件 §b${metadata.name} §4构建插件失败!`)
+ console.ex(error)
}
})
}
+ private checkDepends(depends: string | string[]) {
+ if (!depends) return true
+ for (const depend of depends) { if (!this.metadataMap.has(depend)) return false }
+ return true
+ }
+ private checkNativeDepends(depends: string | string[]) {
+ if (!depends) return true
+ for (const depend of depends) { if (!this.nativePluginManager.has(depend)) return false }
+ return true
+ }
private buildPlugin(metadata: plugin.PluginMetadata) {
- if (!this.loaderMap.has(metadata.type)) { throw new Error(`§4无法加载插件 §c${metadata.name} §4请检查 §c${metadata.type} §4加载器是否正常启用!`) }
if (this.instanceMap.has(metadata.name)) { throw new Error(`Plugin ${metadata.name} is already load from ${metadata.source}...`) }
+ if (!this.loaderMap.has(metadata.type)) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查 §c${metadata.type} §4加载器是否正常启用!`) }
if (!this.serverChecker.check(metadata.servers)) { throw new Error(`§6插件 §b${metadata.name} §c服务器类型不兼容(${metadata.servers.join(',')}) §6忽略加载...`) }
+ if (!this.checkDepends(metadata.depends)) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查依赖 §3${metadata.depends.join(',')} §4是否安装完整!`) }
+ if (!this.checkNativeDepends(metadata.nativeDepends)) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查插件依赖 §3${metadata.nativeDepends.join(',')} §4是否安装完整!`) }
let pluginInstance = this.loaderMap.get(metadata.type).build(metadata)
if (!pluginInstance) { throw new Error(`§4加载器 §c${metadata.type} §4加载插件 §c${metadata.name} §4失败!`) }
this.instanceMap.set(metadata.name, pluginInstance)
diff --git a/packages/spring/src/server.ts b/packages/spring/src/server.ts
index 1c903cba..118eee42 100644
--- a/packages/spring/src/server.ts
+++ b/packages/spring/src/server.ts
@@ -1,31 +1,32 @@
-import { server } from '@ccms/api'
-import { provideSingleton, inject } from '@ccms/container'
-import { NativePluginManager } from '@ccms/api'
+import { constants, server } from '@ccms/api'
+import { provideSingleton, postConstruct, Autowired, Container, ContainerInstance } from '@ccms/container'
import { CommandMap } from './internal/command'
@provideSingleton(server.Server)
-export class SpringServer implements server.Server {
- @inject(CommandMap)
+export class SpringServer extends server.Server {
+ @Autowired(ContainerInstance)
+ private container: Container
+ @Autowired()
private commandMap: CommandMap
+ private nettyPipeline = base.getInstance().getAutowireCapableBeanFactory()
+ private rootLogger = Packages.org.slf4j.LoggerFactory.getLogger("root") || global.logger
+
+ @postConstruct()
+ initialize() {
+ this.container.bind(constants.ServiceIdentifier.NettyPipeline).toConstantValue(this.nettyPipeline)
+ this.container.bind(constants.ServiceIdentifier.RootLogger).toConstantValue(this.rootLogger)
+ }
+
getVersion(): string {
return "SpringFramework"
}
- getPlayer(name: string) {
- throw new Error("Method not implemented.")
- }
- getOnlinePlayers(): any[] {
- throw new Error("Method not implemented.")
- }
getConsoleSender() {
return {
name: 'CONSOLE',
sendMessage: (message: string) => console.console(message)
}
}
- getService(service: string) {
- throw new Error("Method not implemented.")
- }
dispatchCommand(sender: any, command: string): boolean {
let cmd_args = command.split(" ")
return this.commandMap.dispatch(sender, cmd_args.shift(), cmd_args || [])
@@ -33,16 +34,10 @@ export class SpringServer implements server.Server {
dispatchConsoleCommand(command: string): boolean {
return this.dispatchCommand(this.getConsoleSender(), command)
}
- getPluginsFolder(): string {
- throw new Error("Method not implemented.")
- }
- getNativePluginManager(): NativePluginManager {
- throw new Error("Method not implemented.")
- }
getNettyPipeline() {
- return base.getInstance().getAutowireCapableBeanFactory()
+ return this.nettyPipeline
}
getRootLogger() {
- return Packages.org.slf4j.LoggerFactory.getLogger("root") || global.logger
+ return this.rootLogger
}
}