feat: update ms system
This commit is contained in:
parent
6910ea3e26
commit
8f944e0b14
@ -1,4 +1,4 @@
|
|||||||
import { injectable } from "@ccms/container";
|
import { injectable } from "@ccms/container"
|
||||||
|
|
||||||
export namespace channel {
|
export namespace channel {
|
||||||
/**
|
/**
|
||||||
@ -17,32 +17,32 @@ export namespace channel {
|
|||||||
* @param exec 执行器
|
* @param exec 执行器
|
||||||
*/
|
*/
|
||||||
listen(plugin: any, channel: string, exec: ChannelListener) {
|
listen(plugin: any, channel: string, exec: ChannelListener) {
|
||||||
if (!plugin || !plugin.description || !plugin.description.name) throw new TypeError('Plugin can\'t be undefiend!');
|
if (!plugin || !plugin.description || !plugin.description.name) throw new TypeError('Plugin can\'t be undefiend!')
|
||||||
let name = plugin.description.name;
|
let name = plugin.description.name
|
||||||
let listener = this.register(channel, exec)
|
let listener = this.register(channel, exec)
|
||||||
if (!this.listenerMap[name]) this.listenerMap[name] = [];
|
if (!this.listenerMap[name]) this.listenerMap[name] = []
|
||||||
let offExec = () => {
|
let offExec = () => {
|
||||||
this.unregister(channel, listener);
|
this.unregister(channel, listener)
|
||||||
console.debug(`[${name}] unregister channel ${channel}`);
|
console.debug(`[${name}] unregister channel ${channel}`)
|
||||||
};
|
}
|
||||||
var off = {
|
var off = {
|
||||||
channel,
|
channel,
|
||||||
listener,
|
listener,
|
||||||
off: offExec
|
off: offExec
|
||||||
};
|
}
|
||||||
this.listenerMap[name].push(off);
|
this.listenerMap[name].push(off)
|
||||||
console.debug(`[${name}] register channel ${channel} => ${exec.name || '[anonymous]'}`);
|
console.debug(`[${name}] register channel ${channel} => ${exec.name || '[anonymous]'}`)
|
||||||
return off;
|
return off
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 关闭插件注册的通道
|
* 关闭插件注册的通道
|
||||||
* @param plugin 插件
|
* @param plugin 插件
|
||||||
*/
|
*/
|
||||||
disable(plugin: any) {
|
disable(plugin: any) {
|
||||||
var channelCache = this.listenerMap[plugin.description.name];
|
var channelCache = this.listenerMap[plugin.description.name]
|
||||||
if (channelCache) {
|
if (channelCache) {
|
||||||
channelCache.forEach(t => t.off());
|
channelCache.forEach(t => t.off())
|
||||||
delete this.listenerMap[plugin.description.name];
|
delete this.listenerMap[plugin.description.name]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
import { injectable } from '@ccms/container'
|
||||||
|
|
||||||
export namespace chat {
|
export namespace chat {
|
||||||
|
@injectable()
|
||||||
export abstract class Chat {
|
export abstract class Chat {
|
||||||
sendMessage(sender: any, message: string) {
|
sendMessage(sender: any, message: string) {
|
||||||
throw new Error("Method not implemented.")
|
throw new Error("Method not implemented.")
|
||||||
@ -9,7 +12,7 @@ export namespace chat {
|
|||||||
clearActionBar(sender: any) {
|
clearActionBar(sender: any) {
|
||||||
this.sendActionBar(sender, '')
|
this.sendActionBar(sender, '')
|
||||||
}
|
}
|
||||||
sendTitle(sender: any, title: string, subtitle: string = '', fadeIn: number = 1, time: number = 5, fadeOut: number = 1) {
|
sendTitle(sender: any, title: string, subtitle: string = '', fadeIn: number = 20, time: number = 100, fadeOut: number = 20) {
|
||||||
throw new Error("Method not implemented.")
|
throw new Error("Method not implemented.")
|
||||||
}
|
}
|
||||||
clearTitle(sender: any) {
|
clearTitle(sender: any) {
|
||||||
|
@ -130,23 +130,20 @@ export namespace event {
|
|||||||
}
|
}
|
||||||
priority = priority || EventPriority.NORMAL
|
priority = priority || EventPriority.NORMAL
|
||||||
ignoreCancel = ignoreCancel || false
|
ignoreCancel = ignoreCancel || false
|
||||||
|
// @ts-ignore
|
||||||
|
let executor = exec.name || exec.executor || '[anonymous]'
|
||||||
// noinspection JSUnusedGlobalSymbols
|
// noinspection JSUnusedGlobalSymbols
|
||||||
var listener = this.register(eventCls, this.execute(name, exec, eventCls), priority, ignoreCancel)
|
var listener = this.register(eventCls, this.execute(name, exec, eventCls), priority, ignoreCancel)
|
||||||
var listenerMap = this.listenerMap
|
var listenerMap = this.listenerMap
|
||||||
// add to cache Be used for close plugin to close event
|
// add to cache Be used for close plugin to close event
|
||||||
if (!listenerMap[name]) listenerMap[name] = []
|
if (!listenerMap[name]) listenerMap[name] = []
|
||||||
var offExec = () => {
|
var off = () => {
|
||||||
this.unregister(eventCls, listener)
|
this.unregister(eventCls, listener)
|
||||||
console.debug(i18n.translate("ms.api.event.unregister", { name, event: this.class2Name(eventCls), exec: exec.name || '[anonymous]' }))
|
console.debug(i18n.translate("ms.api.event.unregister", { name, event: this.class2Name(eventCls), exec: executor }))
|
||||||
}
|
|
||||||
var off = {
|
|
||||||
event: eventCls,
|
|
||||||
listener: listener,
|
|
||||||
off: offExec
|
|
||||||
}
|
}
|
||||||
listenerMap[name].push(off)
|
listenerMap[name].push(off)
|
||||||
// noinspection JSUnresolvedVariable
|
// noinspection JSUnresolvedVariable
|
||||||
console.debug(i18n.translate("ms.api.event.register", { name, event: this.class2Name(eventCls), exec: exec.name || '[anonymous]' }))
|
console.debug(i18n.translate("ms.api.event.register", { name, event: this.class2Name(eventCls), exec: executor }))
|
||||||
return off
|
return off
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +154,7 @@ export namespace event {
|
|||||||
disable(plugin: any) {
|
disable(plugin: any) {
|
||||||
var eventCache = this.listenerMap[plugin.description.name]
|
var eventCache = this.listenerMap[plugin.description.name]
|
||||||
if (eventCache) {
|
if (eventCache) {
|
||||||
eventCache.forEach(t => t.off())
|
eventCache.forEach(off => off())
|
||||||
delete this.listenerMap[plugin.description.name]
|
delete this.listenerMap[plugin.description.name]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,6 @@ export namespace plugin {
|
|||||||
* 插件加载类型
|
* 插件加载类型
|
||||||
*/
|
*/
|
||||||
type: string
|
type: string
|
||||||
/**
|
|
||||||
* 插件名称
|
|
||||||
*/
|
|
||||||
name?: string
|
|
||||||
/**
|
/**
|
||||||
* 插件文件
|
* 插件文件
|
||||||
*/
|
*/
|
||||||
@ -116,22 +112,22 @@ export namespace plugin {
|
|||||||
* Load 阶段
|
* Load 阶段
|
||||||
* @param plugin 插件
|
* @param plugin 插件
|
||||||
*/
|
*/
|
||||||
load(plugin: Plugin): void
|
load?(plugin: Plugin): void
|
||||||
/**
|
/**
|
||||||
* Enable 阶段
|
* Enable 阶段
|
||||||
* @param plugin 插件
|
* @param plugin 插件
|
||||||
*/
|
*/
|
||||||
enable(plugin: Plugin): void
|
enable?(plugin: Plugin): void
|
||||||
/**
|
/**
|
||||||
* Disable 阶段
|
* Disable 阶段
|
||||||
* @param plugin 插件
|
* @param plugin 插件
|
||||||
*/
|
*/
|
||||||
disable(plugin: Plugin): void
|
disable?(plugin: Plugin): void
|
||||||
/**
|
/**
|
||||||
* Reload 阶段
|
* Reload 阶段
|
||||||
* @param plugin 插件
|
* @param plugin 插件
|
||||||
*/
|
*/
|
||||||
reload(plugin: Plugin): void
|
reload?(plugin: Plugin): void
|
||||||
}
|
}
|
||||||
export interface Plugin {
|
export interface Plugin {
|
||||||
description: PluginMetadata
|
description: PluginMetadata
|
||||||
|
@ -9,7 +9,7 @@ const Messenger = Bukkit.getMessenger()
|
|||||||
export class BukkitChannel extends channel.Channel {
|
export class BukkitChannel extends channel.Channel {
|
||||||
@inject(plugin.PluginInstance)
|
@inject(plugin.PluginInstance)
|
||||||
private pluginInstance: any
|
private pluginInstance: any
|
||||||
|
private cacheChannel = new Map<string, any[]>()
|
||||||
/**
|
/**
|
||||||
* 给玩家发送通道消息
|
* 给玩家发送通道消息
|
||||||
* @param player 接受消息的玩家
|
* @param player 接受消息的玩家
|
||||||
@ -26,15 +26,29 @@ export class BukkitChannel extends channel.Channel {
|
|||||||
* @param listener 监听器
|
* @param listener 监听器
|
||||||
*/
|
*/
|
||||||
register(channel: string, listener: channel.ChannelListener) {
|
register(channel: string, listener: channel.ChannelListener) {
|
||||||
Messenger.registerIncomingPluginChannel(this.pluginInstance, channel, new PluginMessageListener({
|
if (!this.cacheChannel.has(channel)) this.cacheChannel.set(channel, [])
|
||||||
|
this.cacheChannel.get(channel).push(listener)
|
||||||
|
let pluginMessageListener = new PluginMessageListener({
|
||||||
onPluginMessageReceived: (/**String */ channel, /**Player */ player, /**byte[] */data) => {
|
onPluginMessageReceived: (/**String */ channel, /**Player */ player, /**byte[] */data) => {
|
||||||
listener(data, { channel, player, data })
|
try {
|
||||||
|
listener(data, { channel, player, data })
|
||||||
|
} catch (error) {
|
||||||
|
console.ex(error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
|
Messenger.registerIncomingPluginChannel(this.pluginInstance, channel, pluginMessageListener)
|
||||||
Messenger.registerOutgoingPluginChannel(this.pluginInstance, channel)
|
Messenger.registerOutgoingPluginChannel(this.pluginInstance, channel)
|
||||||
|
return pluginMessageListener
|
||||||
}
|
}
|
||||||
unregister(channel: string, listener: any) {
|
unregister(channel: string, listener: any) {
|
||||||
Messenger.unregisterIncomingPluginChannel(this.pluginInstance, channel)
|
if (!this.cacheChannel.has(channel)) return
|
||||||
Messenger.unregisterOutgoingPluginChannel(this.pluginInstance, channel)
|
let cacheListener = this.cacheChannel.get(channel)
|
||||||
|
cacheListener = cacheListener.filter(l => l != listener)
|
||||||
|
Messenger.unregisterIncomingPluginChannel(this.pluginInstance, channel, listener)
|
||||||
|
if (cacheListener.length == 0) {
|
||||||
|
this.cacheChannel.delete(channel)
|
||||||
|
Messenger.unregisterOutgoingPluginChannel(this.pluginInstance, channel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,12 @@ import bukkitChat from './enhance/chat'
|
|||||||
@provideSingleton(chat.Chat)
|
@provideSingleton(chat.Chat)
|
||||||
export class BukkitChat extends chat.Chat {
|
export class BukkitChat extends chat.Chat {
|
||||||
sendMessage(sender: any, message: string) {
|
sendMessage(sender: any, message: string) {
|
||||||
bukkitChat.send(sender, { text: message }, 0)
|
bukkitChat.send(sender, JSON.stringify({ text: message }), 0)
|
||||||
}
|
}
|
||||||
sendActionBar(sender: any, message: string) {
|
sendActionBar(sender: any, message: string) {
|
||||||
bukkitChat.send(sender, { text: message }, 2)
|
bukkitChat.send(sender, JSON.stringify({ text: message }), 2)
|
||||||
}
|
}
|
||||||
sendTitle(sender: any, title: string, subtitle: string = '', fadeIn: number = 1, time: number = 5, fadeOut: number = 1) {
|
sendTitle(sender: any, title: string, subtitle: string = '', fadeIn: number = 20, time: number = 100, fadeOut: number = 20) {
|
||||||
sender.sendTitle(title, subtitle, fadeIn, time, fadeOut)
|
sender.sendTitle(title, subtitle, fadeIn, time, fadeOut)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ let RemapUtils: any
|
|||||||
let playerConnectionFieldName: string
|
let playerConnectionFieldName: string
|
||||||
let sendPacketMethodName: string
|
let sendPacketMethodName: string
|
||||||
|
|
||||||
|
let above_1_16 = false
|
||||||
let downgrade = false
|
let downgrade = false
|
||||||
/**
|
/**
|
||||||
* 获取NMS版本
|
* 获取NMS版本
|
||||||
@ -59,12 +60,18 @@ function init() {
|
|||||||
let packetTypeClass = nmsCls("PacketPlayOutChat")
|
let packetTypeClass = nmsCls("PacketPlayOutChat")
|
||||||
PacketPlayOutChat = Java.type(packetTypeClass.getName())
|
PacketPlayOutChat = Java.type(packetTypeClass.getName())
|
||||||
let packetTypeConstructor: { parameterTypes: any[] }
|
let packetTypeConstructor: { parameterTypes: any[] }
|
||||||
Java.from(packetTypeClass.constructors).forEach(function (c) {
|
let constructors = packetTypeClass.constructors
|
||||||
|
Java.from(constructors).forEach(function (c) {
|
||||||
if (c.parameterTypes.length === 2) {
|
if (c.parameterTypes.length === 2) {
|
||||||
packetTypeConstructor = c
|
packetTypeConstructor = c
|
||||||
}
|
}
|
||||||
|
if (c.parameterTypes.length === 3) {
|
||||||
|
packetTypeConstructor = c
|
||||||
|
above_1_16 = true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
let nmsChatMessageTypeClass = packetTypeConstructor.parameterTypes[1]
|
let parameterTypes = packetTypeConstructor.parameterTypes
|
||||||
|
let nmsChatMessageTypeClass = parameterTypes[1]
|
||||||
if (nmsChatMessageTypeClass.isEnum()) {
|
if (nmsChatMessageTypeClass.isEnum()) {
|
||||||
chatMessageTypes = nmsChatMessageTypeClass.getEnumConstants()
|
chatMessageTypes = nmsChatMessageTypeClass.getEnumConstants()
|
||||||
}
|
}
|
||||||
@ -83,7 +90,13 @@ function json(sender: { name: string }, json: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function send(sender: any, json: any, type: number) {
|
function send(sender: any, json: any, type: number) {
|
||||||
sendPacket(sender, new PacketPlayOutChat(ChatSerializer[nmsChatSerializerMethodName](json), chatMessageTypes == null ? type : chatMessageTypes[type]))
|
let packet
|
||||||
|
if (above_1_16) {
|
||||||
|
packet = new PacketPlayOutChat(ChatSerializer[nmsChatSerializerMethodName](json), chatMessageTypes == null ? type : chatMessageTypes[type], sender.getUniqueId())
|
||||||
|
} else {
|
||||||
|
packet = new PacketPlayOutChat(ChatSerializer[nmsChatSerializerMethodName](json), chatMessageTypes == null ? type : chatMessageTypes[type])
|
||||||
|
}
|
||||||
|
sendPacket(sender, packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendPacket(player: { handle: { [x: string]: { [x: string]: (arg0: any) => void } } }, p: any) {
|
function sendPacket(player: { handle: { [x: string]: { [x: string]: (arg0: any) => void } } }, p: any) {
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
import { server } from '@ccms/api'
|
import { server } from '@ccms/api'
|
||||||
import { Container } from '@ccms/container'
|
import { Container } from '@ccms/container'
|
||||||
|
|
||||||
import { BukkitConsole } from './console';
|
import { BukkitConsole } from './console'
|
||||||
import './event';
|
import './chat'
|
||||||
import './server';
|
import './task'
|
||||||
import './command';
|
import './event'
|
||||||
import './channel';
|
import './server'
|
||||||
import './task';
|
import './command'
|
||||||
|
import './channel'
|
||||||
|
|
||||||
export default function BukkitImpl(container: Container) {
|
export default function BukkitImpl(container: Container) {
|
||||||
container.bind(server.Console).toConstantValue(BukkitConsole);
|
container.bind(server.Console).toConstantValue(BukkitConsole)
|
||||||
}
|
}
|
||||||
|
@ -63,4 +63,7 @@ export class BukkitServer extends server.ReflectServer {
|
|||||||
this.dispatchConsoleCommand(result)
|
this.dispatchConsoleCommand(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tabComplete?(sender: any, input: string, index?: number): string[] {
|
||||||
|
throw new Error("Method not implemented.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
import * as querystring from 'querystring'
|
||||||
|
|
||||||
const URL = Java.type('java.net.URL')
|
const URL = Java.type('java.net.URL')
|
||||||
const Paths = Java.type('java.nio.file.Paths');
|
const Paths = Java.type('java.nio.file.Paths')
|
||||||
const Files = Java.type('java.nio.file.Files');
|
const Files = Java.type('java.nio.file.Files')
|
||||||
const StandardCopyOption = Java.type('java.nio.file.StandardCopyOption');
|
const StandardCopyOption = Java.type('java.nio.file.StandardCopyOption')
|
||||||
|
|
||||||
export type Method =
|
export type Method =
|
||||||
| 'get' | 'GET'
|
| 'get' | 'GET'
|
||||||
@ -13,36 +15,49 @@ export type Method =
|
|||||||
| 'patch' | 'PATCH'
|
| 'patch' | 'PATCH'
|
||||||
|
|
||||||
interface RequestConfig {
|
interface RequestConfig {
|
||||||
url?: string;
|
url?: string
|
||||||
method?: Method;
|
method?: Method
|
||||||
headers?: { [key: string]: string };
|
headers?: { [key: string]: string }
|
||||||
params?: { [key: string]: string };
|
params?: { [key: string]: string }
|
||||||
data?: any;
|
data?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
function request(config: RequestConfig) {
|
function request(config: RequestConfig) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
let xhr = new XMLHttpRequest();
|
let xhr = new XMLHttpRequest()
|
||||||
xhr.open(config.method, config.url, false);
|
xhr.open(config.method, config.url, false)
|
||||||
for (const header in config.headers) {
|
for (const header in config.headers) {
|
||||||
xhr.setRequestHeader(header, config.headers[header]);
|
xhr.setRequestHeader(header, config.headers[header])
|
||||||
}
|
}
|
||||||
xhr.send(typeof config.data === "string" ? config.data : JSON.stringify(config.data));
|
let body = config.data
|
||||||
if ((xhr.getResponseHeader("Content-Type") + '').indexOf('application/json') != -1) {
|
if (body && typeof body !== "string") {
|
||||||
|
switch (config.headers['Content-Type']) {
|
||||||
|
case "application/json":
|
||||||
|
body = JSON.stringify(body)
|
||||||
|
break
|
||||||
|
case "application/x-www-form-urlencoded":
|
||||||
|
body = querystring.encode(body)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhr.send(body)
|
||||||
|
if (xhr.getResponseHeader("Content-Type").indexOf('application/json') != -1) {
|
||||||
xhr.responseType = "json"
|
xhr.responseType = "json"
|
||||||
}
|
}
|
||||||
return xhr.get();
|
return xhr.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
function download(url: string, target: string) {
|
function download(url: string, target: string) {
|
||||||
console.debug(`Start Download file ${target} from ${url}....`)
|
console.debug(`Start Download file ${target} from ${url}....`)
|
||||||
Files.copy(new URL(url).openStream(), Paths.get(target), StandardCopyOption.REPLACE_EXISTING);
|
Files.copy(new URL(url).openStream(), Paths.get(target), StandardCopyOption.REPLACE_EXISTING)
|
||||||
console.debug(`File ${target} Download Complate...`)
|
console.debug(`File ${target} Download Complate...`)
|
||||||
}
|
}
|
||||||
|
|
||||||
function _proxy(method: Method) {
|
function _proxy(method: Method) {
|
||||||
return function (url: string, data?: any, config?: RequestConfig) {
|
return function (url: string, data?: any, config: RequestConfig = {}) {
|
||||||
return request({ url, method, data, ...config });
|
if (!config.headers) { config.headers = {} }
|
||||||
|
config.headers['Content-Type'] = config.headers['Content-Type'] ?? 'application/json'
|
||||||
|
return request({ url, method, data, ...config })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +36,10 @@ export const provideSingletonNamed = (identifier: interfaces.ServiceIdentifier<a
|
|||||||
* @param className Java全类名
|
* @param className Java全类名
|
||||||
*/
|
*/
|
||||||
export const JavaClass = (className: string) => {
|
export const JavaClass = (className: string) => {
|
||||||
return function (target: any, propertyKey: string, index?: number) {
|
return function (target: object, propertyKey: string, index?: number) {
|
||||||
try { target[propertyKey] = Java.type(className).class; return } catch (error) { }
|
try { target[propertyKey] = Java.type(className).class; return } catch (error) { }
|
||||||
try { target[propertyKey] = base.getClass(className); return } catch (error) { }
|
try { target[propertyKey] = base.getClass(className); return } catch (error) { }
|
||||||
console.warn('JavaClass Inject target', target, 'propertyKey', propertyKey, 'failed!')
|
console.warn('JavaClass', className, 'Inject target', target.constructor.name, 'propertyKey', propertyKey, 'failed!')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,10 +48,10 @@ export const JavaClass = (className: string) => {
|
|||||||
* @param className Java 全类名
|
* @param className Java 全类名
|
||||||
*/
|
*/
|
||||||
export const JSClass = (className: string) => {
|
export const JSClass = (className: string) => {
|
||||||
return function (target: any, propertyKey: string, index?: number) {
|
return function (target: object, propertyKey: string, index?: number) {
|
||||||
try { target[propertyKey] = Java.type(className); return } catch (error) { }
|
try { target[propertyKey] = Java.type(className); return } catch (error) { }
|
||||||
try { target[propertyKey] = base.getClass(className).static; return } catch (error) { }
|
try { target[propertyKey] = base.getClass(className).static; return } catch (error) { }
|
||||||
console.warn('JSClass Inject target', target, 'propertyKey', propertyKey, 'failed!')
|
console.warn('JSClass', className, 'Inject target', target.constructor.name, 'propertyKey', propertyKey, 'failed!')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ ms.api.event.not.found: "§6插件 §b{name} §6注册事件 §c{event} §6失
|
|||||||
ms.api.event.execute.slow: "§c注意! §6插件 §b{name} §6处理 §d{event} §6事件 §c耗时 §4{cost}ms !"
|
ms.api.event.execute.slow: "§c注意! §6插件 §b{name} §6处理 §d{event} §6事件 §c耗时 §4{cost}ms !"
|
||||||
ms.api.event.execute.error: "§6插件 §b{name} §6处理 §d{event} §6事件时发生异常 §4{ex}"
|
ms.api.event.execute.error: "§6插件 §b{name} §6处理 §d{event} §6事件时发生异常 §4{ex}"
|
||||||
ms.api.event.listen.plugin.name.empty: "插件名称为空 请检查传入参数!"
|
ms.api.event.listen.plugin.name.empty: "插件名称为空 请检查传入参数!"
|
||||||
ms.api.event.register: "[{name}] 注册事件 {event} => {exec}"
|
ms.api.event.register: "[{name}] 注册事件 {event} => 执行器 {exec}"
|
||||||
ms.api.event.unregister: "[{name}] 注销事件 {event} => {exec}"
|
ms.api.event.unregister: "[{name}] 注销事件 {event} => 执行器 {exec}"
|
||||||
ms.api.command.register.input.error: "CommandExec 必须为一个函数... 输入: {exec}"
|
ms.api.command.register.input.error: "CommandExec 必须为一个函数... 输入: {exec}"
|
||||||
ms.api.command.register: "[{plugin}] 注册命令 {name}({cmd})..."
|
ms.api.command.register: "[{plugin}] 注册命令 {name}({cmd})..."
|
||||||
ms.api.command.unregister: "[{plugin}] 注销命令 {name}..."
|
ms.api.command.unregister: "[{plugin}] 注销命令 {name}..."
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
import '@ccms/nashorn'
|
import '@ccms/nashorn'
|
||||||
|
|
||||||
const URL = Java.type("java.net.URL");
|
const URL = Java.type("java.net.URL")
|
||||||
const Files = Java.type("java.nio.file.Files");
|
const Files = Java.type("java.nio.file.Files")
|
||||||
const StandardCopyOption = Java.type("java.nio.file.StandardCopyOption");
|
const StandardCopyOption = Java.type("java.nio.file.StandardCopyOption")
|
||||||
const JavaString = Java.type("java.lang.String");
|
const JavaString = Java.type("java.lang.String")
|
||||||
const SecureRandom = Java.type("java.security.SecureRandom");
|
const SecureRandom = Java.type("java.security.SecureRandom")
|
||||||
const SSLContext = Java.type("javax.net.ssl.SSLContext");
|
const SSLContext = Java.type("javax.net.ssl.SSLContext")
|
||||||
const HttpsURLConnection = Java.type("javax.net.ssl.HttpsURLConnection");
|
const HttpsURLConnection = Java.type("javax.net.ssl.HttpsURLConnection")
|
||||||
const HostnameVerifier = Java.type("javax.net.ssl.HostnameVerifier");
|
const HostnameVerifier = Java.type("javax.net.ssl.HostnameVerifier")
|
||||||
const X509TrustManager = Java.type("javax.net.ssl.X509TrustManager");
|
const X509TrustManager = Java.type("javax.net.ssl.X509TrustManager")
|
||||||
|
|
||||||
const SocketTimeoutException = Java.type('java.net.SocketTimeoutException');
|
const SocketTimeoutException = Java.type('java.net.SocketTimeoutException')
|
||||||
|
|
||||||
const Callable = Java.type('java.util.concurrent.Callable');
|
const Callable = Java.type('java.util.concurrent.Callable')
|
||||||
const Executors = Java.type('java.util.concurrent.Executors')
|
const Executors = Java.type('java.util.concurrent.Executors')
|
||||||
|
|
||||||
const UTF_8 = "UTF-8"
|
const UTF_8 = "UTF-8"
|
||||||
|
|
||||||
const TrustAnyHostnameVerifier = new HostnameVerifier({ verify: () => true });
|
const TrustAnyHostnameVerifier = new HostnameVerifier({ verify: () => true })
|
||||||
|
|
||||||
const SSLSocketFactory = function initSSLSocketFactory() {
|
const SSLSocketFactory = function initSSLSocketFactory() {
|
||||||
let sslContext = SSLContext.getInstance("TLS");
|
let sslContext = SSLContext.getInstance("TLS")
|
||||||
sslContext.init(null, [new X509TrustManager({
|
sslContext.init(null, [new X509TrustManager({
|
||||||
getAcceptedIssuers: () => null,
|
getAcceptedIssuers: () => null,
|
||||||
checkClientTrusted: () => { },
|
checkClientTrusted: () => { },
|
||||||
checkServerTrusted: () => { }
|
checkServerTrusted: () => { }
|
||||||
})], new SecureRandom());
|
})], new SecureRandom())
|
||||||
return sslContext.getSocketFactory();
|
return sslContext.getSocketFactory()
|
||||||
}();
|
}()
|
||||||
|
|
||||||
interface Future<T> {
|
interface Future<T> {
|
||||||
cancel(): boolean;
|
cancel(): boolean
|
||||||
isCancelled(): boolean;
|
isCancelled(): boolean
|
||||||
isDone(): boolean;
|
isDone(): boolean
|
||||||
get(): T;
|
get(): T
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ReadyState {
|
enum ReadyState {
|
||||||
@ -50,14 +50,14 @@ type RequestMethod =
|
|||||||
| 'options' | 'OPTIONS'
|
| 'options' | 'OPTIONS'
|
||||||
| 'post' | 'POST'
|
| 'post' | 'POST'
|
||||||
| 'put' | 'PUT'
|
| 'put' | 'PUT'
|
||||||
| 'patch' | 'PATCH';
|
| 'patch' | 'PATCH'
|
||||||
type ResponseType =
|
type ResponseType =
|
||||||
| 'arraybuffer'
|
| 'arraybuffer'
|
||||||
| 'blob'
|
| 'blob'
|
||||||
| 'document'
|
| 'document'
|
||||||
| 'json'
|
| 'json'
|
||||||
| 'text'
|
| 'text'
|
||||||
| 'stream';
|
| 'stream'
|
||||||
type EventType =
|
type EventType =
|
||||||
| 'load'
|
| 'load'
|
||||||
| 'error'
|
| 'error'
|
||||||
@ -65,191 +65,191 @@ type EventType =
|
|||||||
| 'progress'
|
| 'progress'
|
||||||
| 'timeout'
|
| 'timeout'
|
||||||
| 'loadend'
|
| 'loadend'
|
||||||
| 'loadstart';
|
| 'loadstart'
|
||||||
type HttpHeader = { [key: string]: string };
|
type HttpHeader = { [key: string]: string }
|
||||||
|
|
||||||
|
|
||||||
const executor = Executors.newCachedThreadPool();
|
const executor = Executors.newCachedThreadPool()
|
||||||
|
|
||||||
export class XMLHttpRequest {
|
export class XMLHttpRequest {
|
||||||
private _timeout: number;
|
private _timeout: number
|
||||||
private _responseType: ResponseType = 'text';
|
private _responseType: ResponseType = 'text';
|
||||||
private _withCredentials: boolean;
|
private _withCredentials: boolean
|
||||||
|
|
||||||
private _readyState: ReadyState = ReadyState.UNSENT;
|
private _readyState: ReadyState = ReadyState.UNSENT;
|
||||||
|
|
||||||
private _method: RequestMethod;
|
private _method: RequestMethod
|
||||||
private _url: string;
|
private _url: string
|
||||||
private _async: boolean;
|
private _async: boolean
|
||||||
private _mimeType: string;
|
private _mimeType: string
|
||||||
private _requestHeaders: HttpHeader = {};
|
private _requestHeaders: HttpHeader = {};
|
||||||
|
|
||||||
private _status: number = 0;
|
private _status: number = 0;
|
||||||
private _statusText: string = null;
|
private _statusText: string = null;
|
||||||
private _response: any;
|
private _response: any
|
||||||
private _responseText: any;
|
private _responseText: any
|
||||||
private _responseURL: string;
|
private _responseURL: string
|
||||||
private _responseHeaders: HttpHeader = {};
|
private _responseHeaders: HttpHeader = {};
|
||||||
|
|
||||||
private _connection = null;
|
private _connection = null;
|
||||||
|
|
||||||
get timeout() {
|
get timeout() {
|
||||||
return this._timeout;
|
return this._timeout
|
||||||
}
|
}
|
||||||
set timeout(timeout: number) {
|
set timeout(timeout: number) {
|
||||||
this._timeout = timeout
|
this._timeout = timeout
|
||||||
}
|
}
|
||||||
get readyState() {
|
get readyState() {
|
||||||
return this._readyState;
|
return this._readyState
|
||||||
}
|
}
|
||||||
set responseType(type: ResponseType) {
|
set responseType(type: ResponseType) {
|
||||||
this._responseType = type;
|
this._responseType = type
|
||||||
}
|
}
|
||||||
get responseType() {
|
get responseType() {
|
||||||
return this._responseType;
|
return this._responseType
|
||||||
}
|
}
|
||||||
|
|
||||||
get status() {
|
get status() {
|
||||||
return this._status;
|
return this._status
|
||||||
}
|
}
|
||||||
get statusText() {
|
get statusText() {
|
||||||
return this._statusText;
|
return this._statusText
|
||||||
}
|
}
|
||||||
get response() {
|
get response() {
|
||||||
return this._response || this.get();
|
return this._response || this.get()
|
||||||
}
|
}
|
||||||
get responseText() {
|
get responseText() {
|
||||||
return this._responseText;
|
return this._responseText
|
||||||
}
|
}
|
||||||
get responseXML() {
|
get responseXML() {
|
||||||
return this._response;
|
return this._response
|
||||||
}
|
}
|
||||||
get responseURL() {
|
get responseURL() {
|
||||||
return this._responseURL;
|
return this._responseURL
|
||||||
}
|
}
|
||||||
|
|
||||||
public onload: () => void;
|
public onload: () => void
|
||||||
public onerror: (ex: Error) => void;
|
public onerror: (ex: Error) => void
|
||||||
public onabort: () => void;
|
public onabort: () => void
|
||||||
public onprogress: () => void;
|
public onprogress: () => void
|
||||||
public ontimeout: (ex: Error) => void;
|
public ontimeout: (ex: Error) => void
|
||||||
public onloadend: () => void;
|
public onloadend: () => void
|
||||||
public onloadstart: () => void;
|
public onloadstart: () => void
|
||||||
public onreadystatechange: () => void;
|
public onreadystatechange: () => void
|
||||||
|
|
||||||
setRequestHeader(key: string, val: string) {
|
setRequestHeader(key: string, val: string) {
|
||||||
this._requestHeaders[key] = val;
|
this._requestHeaders[key] = val
|
||||||
}
|
}
|
||||||
getResponseHeader(key: string): string {
|
getResponseHeader(key: string): string {
|
||||||
return this._responseHeaders[key];
|
return this._responseHeaders[key]
|
||||||
}
|
}
|
||||||
getAllResponseHeaders(): any {
|
getAllResponseHeaders(): any {
|
||||||
return this._responseHeaders;
|
return this._responseHeaders
|
||||||
}
|
}
|
||||||
addEventListener(event: EventType, callback: Function) {
|
addEventListener(event: EventType, callback: Function) {
|
||||||
this[`on${event.toLowerCase()}`] = callback;
|
this[`on${event.toLowerCase()}`] = callback
|
||||||
}
|
}
|
||||||
overrideMimeType(mimeType: string) {
|
overrideMimeType(mimeType: string) {
|
||||||
this._mimeType = mimeType;
|
this._mimeType = mimeType
|
||||||
}
|
}
|
||||||
open(method: RequestMethod, url: string, async: boolean = true, user?: string, password?: string) {
|
open(method: RequestMethod, url: string, async: boolean = true, user?: string, password?: string) {
|
||||||
if (this._readyState !== ReadyState.UNSENT) { throw new Error(`Error Status ${this._readyState}!`) }
|
if (this._readyState !== ReadyState.UNSENT) { throw new Error(`Error Status ${this._readyState}!`) }
|
||||||
|
|
||||||
this._method = method;
|
this._method = method
|
||||||
this._url = url;
|
this._url = url
|
||||||
this._async = async;
|
this._async = async
|
||||||
|
|
||||||
this._connection = new URL(this._url).openConnection()
|
this._connection = new URL(this._url).openConnection()
|
||||||
if (this._connection instanceof HttpsURLConnection) {
|
if (this._connection instanceof HttpsURLConnection) {
|
||||||
this._connection.setHostnameVerifier(TrustAnyHostnameVerifier);
|
this._connection.setHostnameVerifier(TrustAnyHostnameVerifier)
|
||||||
this._connection.setSSLSocketFactory(SSLSocketFactory);
|
this._connection.setSSLSocketFactory(SSLSocketFactory)
|
||||||
}
|
}
|
||||||
this._connection.setRequestMethod(this._method);
|
this._connection.setRequestMethod(this._method)
|
||||||
this._connection.setDoOutput(true);
|
this._connection.setDoOutput(true)
|
||||||
this._connection.setDoInput(true);
|
this._connection.setDoInput(true)
|
||||||
this._connection.setConnectTimeout(this._timeout);
|
this._connection.setConnectTimeout(this._timeout)
|
||||||
this._connection.setReadTimeout(this._timeout);
|
this._connection.setReadTimeout(this._timeout)
|
||||||
|
|
||||||
this.setReadyState(ReadyState.OPENED);
|
this.setReadyState(ReadyState.OPENED)
|
||||||
}
|
}
|
||||||
send(body?: string | object): Future<string> {
|
send(body?: string | object): Future<string> {
|
||||||
for (const header in this._requestHeaders) {
|
for (const header in this._requestHeaders) {
|
||||||
this._connection.setRequestProperty(header, this._requestHeaders[header]);
|
this._connection.setRequestProperty(header, this._requestHeaders[header])
|
||||||
}
|
}
|
||||||
if (this._readyState !== ReadyState.OPENED) { throw new Error(`Error Status ${this._readyState}!`) }
|
if (this._readyState !== ReadyState.OPENED) { throw new Error(`Error Status ${this._readyState}!`) }
|
||||||
let future = executor.submit(new Callable({ call: () => this._send(body) }));
|
let future = executor.submit(new Callable({ call: () => this._send(body) }))
|
||||||
if (!this._async) { future.get() }
|
if (!this._async) { future.get() }
|
||||||
return future;
|
return future
|
||||||
}
|
}
|
||||||
get() {
|
get() {
|
||||||
if (this._response === undefined) {
|
if (this._response === undefined) {
|
||||||
switch (this._responseType) {
|
switch (this._responseType) {
|
||||||
case "json":
|
case "json":
|
||||||
return this._response = JSON.parse(this._responseText);
|
return this._response = JSON.parse(this._responseText)
|
||||||
case "text":
|
case "text":
|
||||||
return this._response = this._responseText;
|
return this._response = this._responseText
|
||||||
default:
|
default:
|
||||||
throw Error(`Unsupport ResponseType: ${this._responseType} !`)
|
throw Error(`Unsupport ResponseType: ${this._responseType} !`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this._response;
|
return this._response
|
||||||
}
|
}
|
||||||
abort() {
|
abort() {
|
||||||
this._connection.disconnect();
|
this._connection.disconnect()
|
||||||
this.onabort && this.onabort();
|
this.onabort && this.onabort()
|
||||||
}
|
}
|
||||||
|
|
||||||
private _send(body?: string | object) {
|
private _send(body?: string | object) {
|
||||||
try {
|
try {
|
||||||
this._connection.connect();
|
this._connection.connect()
|
||||||
this.onloadstart && this.onloadstart();
|
this.onloadstart && this.onloadstart()
|
||||||
if (body) {
|
if (body) {
|
||||||
let bodyType = Object.prototype.toString.call(body);
|
let bodyType = Object.prototype.toString.call(body)
|
||||||
if (typeof body !== "string") { throw new Error(`body(${bodyType}) must be string!`) }
|
if (typeof body !== "string") { throw new Error(`body(${bodyType}) must be string!`) }
|
||||||
var out = this._connection.getOutputStream();
|
var out = this._connection.getOutputStream()
|
||||||
out.write(new JavaString(body).getBytes(UTF_8));
|
out.write(new JavaString(body).getBytes(UTF_8))
|
||||||
out.flush();
|
out.flush()
|
||||||
out.close();
|
out.close()
|
||||||
}
|
}
|
||||||
this.setReadyState(ReadyState.LOADING);
|
this.setReadyState(ReadyState.LOADING)
|
||||||
this._status = this._connection.getResponseCode();
|
this._status = this._connection.getResponseCode()
|
||||||
this._statusText = this._connection.getResponseMessage();
|
this._statusText = this._connection.getResponseMessage()
|
||||||
if (this._status >= 0 && this._status < 300) {
|
if (this._status >= 0 && this._status < 300) {
|
||||||
this._responseText = this.readOutput(this._connection.getInputStream());
|
this._responseText = this.readOutput(this._connection.getInputStream())
|
||||||
} else if (this._status >= 300 && this._status < 400) {
|
} else if (this._status >= 300 && this._status < 400) {
|
||||||
this._responseURL = this.getResponseHeader('Location');
|
this._responseURL = this.getResponseHeader('Location')
|
||||||
} else {
|
} else {
|
||||||
this._responseText = this.readOutput(this._connection.getErrorStream());
|
this._responseText = this.readOutput(this._connection.getErrorStream())
|
||||||
}
|
}
|
||||||
this.setResponseHeaders(this._connection.getHeaderFields());
|
this.setResponseHeaders(this._connection.getHeaderFields())
|
||||||
this.onloadend && this.onloadend();
|
this.onloadend && this.onloadend()
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
if (ex instanceof SocketTimeoutException && this.ontimeout) {
|
if (ex instanceof SocketTimeoutException && this.ontimeout) {
|
||||||
return this.ontimeout(ex)
|
return this.ontimeout(ex)
|
||||||
} else if (this.onerror) {
|
} else if (this.onerror) {
|
||||||
return this.onerror(ex);
|
return this.onerror(ex)
|
||||||
}
|
}
|
||||||
throw ex;
|
throw ex
|
||||||
} finally {
|
} finally {
|
||||||
this._connection.disconnect();
|
this._connection.disconnect()
|
||||||
this.setReadyState(ReadyState.DONE);
|
this.setReadyState(ReadyState.DONE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private setResponseHeaders(header: any) {
|
private setResponseHeaders(header: any) {
|
||||||
header.forEach((key: string | number, value: string | any[]) => {
|
header.forEach((key: string | number, value: string | any[]) => {
|
||||||
this._responseHeaders[key] = value[value.length - 1]
|
this._responseHeaders[key + ''] = value[value.length - 1] + ''
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private setReadyState(state: ReadyState) {
|
private setReadyState(state: ReadyState) {
|
||||||
this._readyState = state;
|
this._readyState = state
|
||||||
this.onreadystatechange && this.onreadystatechange();
|
this.onreadystatechange && this.onreadystatechange()
|
||||||
}
|
}
|
||||||
|
|
||||||
private readOutput(input: any) {
|
private readOutput(input: any) {
|
||||||
var tempFile = Files.createTempFile('xhr', '.response');
|
var tempFile = Files.createTempFile('xhr', '.response')
|
||||||
Files.copy(input, tempFile, StandardCopyOption['REPLACE_EXISTING']); tempFile.toFile().deleteOnExit();
|
Files.copy(input, tempFile, StandardCopyOption['REPLACE_EXISTING']); tempFile.toFile().deleteOnExit()
|
||||||
return new JavaString(Files.readAllBytes(tempFile), 'UTF-8');
|
return new JavaString(Files.readAllBytes(tempFile), 'UTF-8')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ export function plugin(metadata: pluginApi.PluginMetadata | any) {
|
|||||||
export function cmd(metadata: interfaces.CommandMetadata = {}) {
|
export function cmd(metadata: interfaces.CommandMetadata = {}) {
|
||||||
return function (target: any, key: string, value: any) {
|
return function (target: any, key: string, value: any) {
|
||||||
metadata.name = metadata.name || key
|
metadata.name = metadata.name || key
|
||||||
|
metadata.target = target
|
||||||
metadata.executor = key
|
metadata.executor = key
|
||||||
metadata.paramtypes = Reflect.getMetadata("design:paramtypes", target, key)
|
metadata.paramtypes = Reflect.getMetadata("design:paramtypes", target, key)
|
||||||
const previousMetadata: Map<string, interfaces.CommandMetadata> = getPluginCommandMetadata(target)
|
const previousMetadata: Map<string, interfaces.CommandMetadata> = getPluginCommandMetadata(target)
|
||||||
@ -46,6 +47,7 @@ export function tab(metadata: interfaces.CommandMetadata = {}) {
|
|||||||
return function (target: any, key: string, value: any) {
|
return function (target: any, key: string, value: any) {
|
||||||
metadata.name = metadata.name || (key.startsWith('tab') ? key.split('tab', 2)[1] : key)
|
metadata.name = metadata.name || (key.startsWith('tab') ? key.split('tab', 2)[1] : key)
|
||||||
if (!metadata.name) { return }
|
if (!metadata.name) { return }
|
||||||
|
metadata.target = target
|
||||||
metadata.executor = key
|
metadata.executor = key
|
||||||
metadata.paramtypes = Reflect.getMetadata("design:paramtypes", target, key)
|
metadata.paramtypes = Reflect.getMetadata("design:paramtypes", target, key)
|
||||||
const previousMetadata: Map<string, interfaces.CommandMetadata> = getPluginTabCompleterMetadata(target)
|
const previousMetadata: Map<string, interfaces.CommandMetadata> = getPluginTabCompleterMetadata(target)
|
||||||
@ -61,9 +63,11 @@ export function tab(metadata: interfaces.CommandMetadata = {}) {
|
|||||||
export function listener(metadata: interfaces.ListenerMetadata = {}) {
|
export function listener(metadata: interfaces.ListenerMetadata = {}) {
|
||||||
return function (target: any, key: string, value: any) {
|
return function (target: any, key: string, value: any) {
|
||||||
metadata.name = metadata.name || key
|
metadata.name = metadata.name || key
|
||||||
|
metadata.target = target
|
||||||
metadata.executor = key
|
metadata.executor = key
|
||||||
const previousMetadata: interfaces.ListenerMetadata[] = getPluginListenerMetadata(target)
|
const previousMetadata: interfaces.ListenerMetadata[] = getPluginListenerMetadata(target)
|
||||||
Reflect.defineMetadata(METADATA_KEY.listener, [metadata, ...previousMetadata], target.constructor)
|
Reflect.defineMetadata(METADATA_KEY.listener, [metadata, ...previousMetadata], target.constructor)
|
||||||
|
Reflect.defineMetadata(METADATA_KEY.listener, metadata, target[key])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,10 @@ export class PluginEventManager {
|
|||||||
// ignore space listener
|
// ignore space listener
|
||||||
if (!this.ServerChecker.check(event.servers)) { continue }
|
if (!this.ServerChecker.check(event.servers)) { continue }
|
||||||
// here must bind this to pluginInstance
|
// here must bind this to pluginInstance
|
||||||
this.EventManager.listen(pluginInstance, event.name, pluginInstance[event.executor].bind(pluginInstance), event.priority, event.ignoreCancel)
|
let exec = event.target[event.executor]
|
||||||
|
let execBinded = exec.bind(pluginInstance)
|
||||||
|
execBinded.executor = event.executor
|
||||||
|
exec.off = this.EventManager.listen(pluginInstance, event.name, execBinded, event.priority, event.ignoreCancel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,10 @@ export namespace interfaces {
|
|||||||
public disable() { }
|
public disable() { }
|
||||||
}
|
}
|
||||||
export interface ExecMetadata extends plugin.BaseMetadata {
|
export interface ExecMetadata extends plugin.BaseMetadata {
|
||||||
|
/**
|
||||||
|
* 执行器所在对象 用于绑定this
|
||||||
|
*/
|
||||||
|
target?: any
|
||||||
/**
|
/**
|
||||||
* 执行器
|
* 执行器
|
||||||
*/
|
*/
|
||||||
@ -68,5 +72,4 @@ export namespace interfaces {
|
|||||||
*/
|
*/
|
||||||
readonly?: boolean
|
readonly?: boolean
|
||||||
}
|
}
|
||||||
export type PluginLike = Plugin | string
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { plugin } from "@ccms/api"
|
import { plugin } from "@ccms/api"
|
||||||
import { provideSingleton } from "@ccms/container"
|
import { provideSingletonNamed } from "@ccms/container"
|
||||||
|
|
||||||
@provideSingleton(plugin.PluginLoader)
|
const LOADER_TYPE_NAME = 'basic'
|
||||||
|
|
||||||
|
@provideSingletonNamed(plugin.PluginLoader, LOADER_TYPE_NAME)
|
||||||
export class BasicLoader implements plugin.PluginLoader {
|
export class BasicLoader implements plugin.PluginLoader {
|
||||||
type: string = 'basic'
|
type: string = LOADER_TYPE_NAME
|
||||||
|
|
||||||
private pluginRequireMap: Map<string, any>
|
private pluginRequireMap: Map<string, any>
|
||||||
|
|
||||||
@ -22,8 +24,4 @@ export class BasicLoader implements plugin.PluginLoader {
|
|||||||
build(metadata: plugin.PluginMetadata) {
|
build(metadata: plugin.PluginMetadata) {
|
||||||
return this.pluginRequireMap.get(metadata.source.toString())
|
return this.pluginRequireMap.get(metadata.source.toString())
|
||||||
}
|
}
|
||||||
load(plugin: plugin.Plugin): void { }
|
|
||||||
enable(plugin: plugin.Plugin): void { }
|
|
||||||
disable(plugin: plugin.Plugin): void { }
|
|
||||||
reload(plugin: plugin.Plugin): void { }
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
import { plugin, server } from "@ccms/api"
|
import { plugin, server } from "@ccms/api"
|
||||||
import { inject, ContainerInstance, Container, provideSingleton } from "@ccms/container"
|
import { inject, ContainerInstance, Container, provideSingletonNamed } from "@ccms/container"
|
||||||
|
|
||||||
import { interfaces } from "../interfaces"
|
import { interfaces } from "../interfaces"
|
||||||
import { getPluginStageMetadata, getPluginSources } from "../utils"
|
import { getPluginStageMetadata, getPluginSources } from "../utils"
|
||||||
|
|
||||||
@provideSingleton(plugin.PluginLoader)
|
const LOADER_TYPE_NAME = 'ioc'
|
||||||
|
|
||||||
|
@provideSingletonNamed(plugin.PluginLoader, LOADER_TYPE_NAME)
|
||||||
export class IocLoader implements plugin.PluginLoader {
|
export class IocLoader implements plugin.PluginLoader {
|
||||||
type: string = 'ioc'
|
type: string = LOADER_TYPE_NAME
|
||||||
@inject(ContainerInstance)
|
@inject(ContainerInstance)
|
||||||
private container: Container
|
private container: Container
|
||||||
@inject(server.ServerType)
|
@inject(server.ServerChecker)
|
||||||
private serverType: string
|
private serverChecker: server.ServerChecker
|
||||||
|
|
||||||
private pluginMetadataMap: Map<string, plugin.PluginMetadata>
|
private pluginMetadataMap: Map<string, plugin.PluginMetadata>
|
||||||
|
|
||||||
@ -28,7 +30,6 @@ export class IocLoader implements plugin.PluginLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
build(metadata: plugin.PluginMetadata) {
|
build(metadata: plugin.PluginMetadata) {
|
||||||
if (!this.allowProcess(metadata.servers)) { return }
|
|
||||||
let pluginInstance: plugin.Plugin
|
let pluginInstance: plugin.Plugin
|
||||||
try {
|
try {
|
||||||
this.bindPlugin(metadata)
|
this.bindPlugin(metadata)
|
||||||
@ -73,23 +74,10 @@ export class IocLoader implements plugin.PluginLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private allowProcess(servers: string[]) {
|
|
||||||
// Not set servers -> allow
|
|
||||||
if (!servers || !servers.length) return true
|
|
||||||
// include !type -> deny
|
|
||||||
let denyServers = servers.filter(svr => svr.startsWith("!"))
|
|
||||||
if (denyServers.length !== 0) {
|
|
||||||
return !denyServers.includes(`!${this.serverType}`)
|
|
||||||
} else {
|
|
||||||
// only include -> allow
|
|
||||||
return servers.includes(this.serverType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private stage(pluginInstance: plugin.Plugin, stageName: string) {
|
private stage(pluginInstance: plugin.Plugin, stageName: string) {
|
||||||
let stages = getPluginStageMetadata(pluginInstance, stageName)
|
let stages = getPluginStageMetadata(pluginInstance, stageName)
|
||||||
for (const stage of stages) {
|
for (const stage of stages) {
|
||||||
if (!this.allowProcess(stage.servers)) { continue }
|
if (!this.serverChecker.check(stage.servers)) { continue }
|
||||||
console.i18n("ms.plugin.manager.stage.exec", { plugin: pluginInstance.description.name, name: stage.executor, stage: stageName, servers: stage.servers })
|
console.i18n("ms.plugin.manager.stage.exec", { plugin: pluginInstance.description.name, name: stage.executor, stage: stageName, servers: stage.servers })
|
||||||
try {
|
try {
|
||||||
pluginInstance[stage.executor].apply(pluginInstance)
|
pluginInstance[stage.executor].apply(pluginInstance)
|
||||||
|
@ -19,6 +19,8 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
|||||||
private serverType: string
|
private serverType: string
|
||||||
@inject(event.Event)
|
@inject(event.Event)
|
||||||
private EventManager: event.Event
|
private EventManager: event.Event
|
||||||
|
@inject(server.ServerChecker)
|
||||||
|
private serverChecker: server.ServerChecker
|
||||||
|
|
||||||
@inject(PluginCommandManager)
|
@inject(PluginCommandManager)
|
||||||
private commandManager: PluginCommandManager
|
private commandManager: PluginCommandManager
|
||||||
@ -74,7 +76,7 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
|||||||
try {
|
try {
|
||||||
this.loadPlugin(scanner.load(loadMetadata))
|
this.loadPlugin(scanner.load(loadMetadata))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`plugin scanner ${scanner.type} load ${loadMetadata.name} occurred error ${error}`)
|
console.error(`plugin scanner ${scanner.type} load ${loadMetadata.file} occurred error ${error}`)
|
||||||
console.ex(error)
|
console.ex(error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -102,7 +104,7 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
|||||||
process.emit(`plugin.before.${stage}`, plugin)
|
process.emit(`plugin.before.${stage}`, plugin)
|
||||||
this.runCatch(plugin, stage)
|
this.runCatch(plugin, stage)
|
||||||
this.runCatch(plugin, `${this.serverType}${stage}`)
|
this.runCatch(plugin, `${this.serverType}${stage}`)
|
||||||
plugin.description.loadMetadata.loader[stage](plugin)
|
plugin.description.loadMetadata.loader[stage]?.(plugin)
|
||||||
process.emit(`plugin.after.${stage}`, plugin)
|
process.emit(`plugin.after.${stage}`, plugin)
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.i18n("ms.plugin.manager.stage.exec.error", { plugin: plugin.description.name, executor: stage, error: ex })
|
console.i18n("ms.plugin.manager.stage.exec.error", { plugin: plugin.description.name, executor: stage, error: ex })
|
||||||
@ -112,7 +114,7 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
|||||||
|
|
||||||
private loadPlugin(loadMetadata: plugin.PluginLoadMetadata) {
|
private loadPlugin(loadMetadata: plugin.PluginLoadMetadata) {
|
||||||
if (!loadMetadata) { throw new Error('loadMetadata can\'t be undefiend when loadPlugin!') }
|
if (!loadMetadata) { throw new Error('loadMetadata can\'t be undefiend when loadPlugin!') }
|
||||||
if (loadMetadata.loaded) { throw new Error(`Plugin ${loadMetadata.name} is already loaded by ${loadMetadata.loader?.type}!`) }
|
if (loadMetadata.loaded) { throw new Error(`Plugin file ${loadMetadata.file} is already loaded by ${loadMetadata.loader?.type}!`) }
|
||||||
try {
|
try {
|
||||||
for (const [, loader] of this.loaderMap) {
|
for (const [, loader] of this.loaderMap) {
|
||||||
if (this.loaderRequirePlugin(loadMetadata, loader)?.loaded) return loadMetadata.metadata
|
if (this.loaderRequirePlugin(loadMetadata, loader)?.loaded) return loadMetadata.metadata
|
||||||
@ -215,16 +217,17 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
|||||||
try {
|
try {
|
||||||
this.buildPlugin(metadata)
|
this.buildPlugin(metadata)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.console(error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildPlugin(metadata: plugin.PluginMetadata) {
|
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.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.serverChecker.check(metadata.servers)) { throw new Error(`§6插件 §b${metadata.name} §c服务器类型不兼容(${metadata.servers.join(',')}) §6忽略加载...`) }
|
||||||
let pluginInstance = this.loaderMap.get(metadata.type).build(metadata)
|
let pluginInstance = this.loaderMap.get(metadata.type).build(metadata)
|
||||||
if (!pluginInstance) { throw new Error(`§4加载器 §c${metadata.type} §4加载插件 §c${metadata.name} §4失败!`) }
|
if (!pluginInstance) { throw new Error(`§4加载器 §c${metadata.type} §4加载插件 §c${metadata.name} §4失败!`) }
|
||||||
if (this.instanceMap.has(metadata.name)) { throw new Error(`Plugin ${metadata.name} is already load from ${metadata.source}...`) }
|
|
||||||
this.instanceMap.set(metadata.name, pluginInstance)
|
this.instanceMap.set(metadata.name, pluginInstance)
|
||||||
return pluginInstance
|
return pluginInstance
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,11 @@ import { plugin } from "@ccms/api"
|
|||||||
import * as fs from '@ccms/common/dist/fs'
|
import * as fs from '@ccms/common/dist/fs'
|
||||||
import { provideSingletonNamed } from "@ccms/container"
|
import { provideSingletonNamed } from "@ccms/container"
|
||||||
|
|
||||||
@provideSingletonNamed(plugin.PluginScanner, 'file')
|
const SCANNER_TYPE_NAME = 'file'
|
||||||
|
|
||||||
|
@provideSingletonNamed(plugin.PluginScanner, SCANNER_TYPE_NAME)
|
||||||
export class JSFileScanner implements plugin.PluginScanner {
|
export class JSFileScanner implements plugin.PluginScanner {
|
||||||
type: string = 'file'
|
type: string = SCANNER_TYPE_NAME
|
||||||
|
|
||||||
scan(target: any): plugin.PluginLoadMetadata[] {
|
scan(target: any): plugin.PluginLoadMetadata[] {
|
||||||
return this.scanFolder(fs.concat(root, target)).map((file) => this.read(file))
|
return this.scanFolder(fs.concat(root, target)).map((file) => this.read(file))
|
||||||
|
Loading…
Reference in New Issue
Block a user