feat: backup plugins
Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
parent
bf3638dda0
commit
5f0c3bbdd4
@ -1,3 +1,4 @@
|
|||||||
|
/// <reference types="@ccms/nashorn" />
|
||||||
/// <reference types="@ccms/types/dist/typings/bukkit" />
|
/// <reference types="@ccms/types/dist/typings/bukkit" />
|
||||||
/// <reference types="@ccms/types/dist/typings/sponge" />
|
/// <reference types="@ccms/types/dist/typings/sponge" />
|
||||||
/// <reference types="@ccms/types/dist/typings/bungee" />
|
/// <reference types="@ccms/types/dist/typings/bungee" />
|
||||||
@ -56,7 +57,7 @@ export class MiaoConsole extends interfaces.Plugin {
|
|||||||
this.token = Java.type('java.util.UUID').randomUUID().toString()
|
this.token = Java.type('java.util.UUID').randomUUID().toString()
|
||||||
this.logger.console(`§6已生成随机Token: §3${this.token} §c重启后或重新生成后失效!`)
|
this.logger.console(`§6已生成随机Token: §3${this.token} §c重启后或重新生成后失效!`)
|
||||||
}
|
}
|
||||||
global.eventCenter.on('log', (msg) => {
|
process.on('message', (msg) => {
|
||||||
this.logCache.push(msg)
|
this.logCache.push(msg)
|
||||||
if (this.logCache.length > 30) {
|
if (this.logCache.length > 30) {
|
||||||
this.logCache = this.logCache.slice(this.logCache.length - 30, this.logCache.length)
|
this.logCache = this.logCache.slice(this.logCache.length - 30, this.logCache.length)
|
||||||
@ -130,7 +131,7 @@ export class MiaoConsole extends interfaces.Plugin {
|
|||||||
let ProxyAppender = Java.extend(AbstractAppender, {
|
let ProxyAppender = Java.extend(AbstractAppender, {
|
||||||
append: (logEvent) => {
|
append: (logEvent) => {
|
||||||
if (logEvent.level.intLevel() <= Level.INFO.intLevel()) {
|
if (logEvent.level.intLevel() <= Level.INFO.intLevel()) {
|
||||||
global.eventCenter.emit('log', logEvent.getMessage().getFormattedMessage())
|
process.emit('message', logEvent.getMessage().getFormattedMessage())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -146,7 +147,7 @@ export class MiaoConsole extends interfaces.Plugin {
|
|||||||
if (this.rootLogger) {
|
if (this.rootLogger) {
|
||||||
let AbstractHandler = Java.type('java.util.logging.Handler')
|
let AbstractHandler = Java.type('java.util.logging.Handler')
|
||||||
let ProxyHandler = Java.extend(AbstractHandler, {
|
let ProxyHandler = Java.extend(AbstractHandler, {
|
||||||
publish: (record) => global.eventCenter.emit('log', record.getMessage()),
|
publish: (record) => process.emit('message', record.getMessage()),
|
||||||
flush: () => { },
|
flush: () => { },
|
||||||
close: () => { }
|
close: () => { }
|
||||||
})
|
})
|
||||||
@ -162,7 +163,7 @@ export class MiaoConsole extends interfaces.Plugin {
|
|||||||
if (this.rootLogger) {
|
if (this.rootLogger) {
|
||||||
let AppenderBase = Java.type('ch.qos.logback.core.AppenderBase')
|
let AppenderBase = Java.type('ch.qos.logback.core.AppenderBase')
|
||||||
let ProxyAppender = Java.extend(AppenderBase, {
|
let ProxyAppender = Java.extend(AppenderBase, {
|
||||||
append: (logEvent) => global.eventCenter.emit('log', logEvent.getFormattedMessage())
|
append: (logEvent) => process.emit('message', logEvent.getFormattedMessage())
|
||||||
})
|
})
|
||||||
this.appender = new ProxyAppender()
|
this.appender = new ProxyAppender()
|
||||||
this.appender.start()
|
this.appender.start()
|
||||||
@ -175,7 +176,7 @@ export class MiaoConsole extends interfaces.Plugin {
|
|||||||
disable() {
|
disable() {
|
||||||
if (this.socketIOServer) {
|
if (this.socketIOServer) {
|
||||||
this.socketIOServer.close()
|
this.socketIOServer.close()
|
||||||
global.eventCenter.removeAllListeners('log')
|
process.removeAllListeners('message')
|
||||||
}
|
}
|
||||||
if (this.container.isBound(io.Instance)) {
|
if (this.container.isBound(io.Instance)) {
|
||||||
this.container.unbind(io.Instance)
|
this.container.unbind(io.Instance)
|
||||||
@ -220,7 +221,7 @@ export class MiaoConsole extends interfaces.Plugin {
|
|||||||
|
|
||||||
startSocketIOServer() {
|
startSocketIOServer() {
|
||||||
let namespace = this.socketIOServer.of('/MiaoConsole')
|
let namespace = this.socketIOServer.of('/MiaoConsole')
|
||||||
global.eventCenter.on('log', (msg) => namespace.emit('log', msg))
|
process.on('message', (msg) => namespace.emit('log', msg))
|
||||||
namespace.on('connect', (client: SocketIOSocket) => {
|
namespace.on('connect', (client: SocketIOSocket) => {
|
||||||
if (!this.token) {
|
if (!this.token) {
|
||||||
this.logger.console(`§6客户端 §b${client.id} §a请求连接 §4服务器尚未设置 Token 无法连接!`)
|
this.logger.console(`§6客户端 §b${client.id} §a请求连接 §4服务器尚未设置 Token 无法连接!`)
|
||||||
@ -249,6 +250,9 @@ export class MiaoConsole extends interfaces.Plugin {
|
|||||||
setTimeout(() => this.server.dispatchConsoleCommand(cmd), 0)
|
setTimeout(() => this.server.dispatchConsoleCommand(cmd), 0)
|
||||||
client.emit('log', `§6命令: §b${cmd} §a执行成功!`)
|
client.emit('log', `§6命令: §b${cmd} §a执行成功!`)
|
||||||
})
|
})
|
||||||
|
client.on('tabComplate', (input, index, callback) => {
|
||||||
|
callback && callback(this.server.tabComplete(this.server.getConsoleSender(), input, index))
|
||||||
|
})
|
||||||
client.on('exec', (code) => {
|
client.on('exec', (code) => {
|
||||||
try {
|
try {
|
||||||
client.emit('log', this.runCode(code, client.nsp, client))
|
client.emit('log', this.runCode(code, client.nsp, client))
|
||||||
@ -273,7 +277,7 @@ export class MiaoConsole extends interfaces.Plugin {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
client.on('ls', (file: string, fn) => {
|
client.on('ls', (file: string, fn) => {
|
||||||
let dir = fs.file(file);
|
let dir = fs.file(file)
|
||||||
if (!dir.isDirectory()) {
|
if (!dir.isDirectory()) {
|
||||||
return fn(undefined, `${file} 不是一个目录!`)
|
return fn(undefined, `${file} 不是一个目录!`)
|
||||||
}
|
}
|
||||||
@ -309,10 +313,9 @@ export class MiaoConsole extends interfaces.Plugin {
|
|||||||
if (this.serverType == "spring") {
|
if (this.serverType == "spring") {
|
||||||
var dbm = container.get(api.database.DataBaseManager)
|
var dbm = container.get(api.database.DataBaseManager)
|
||||||
var db = dbm.getMainDatabase()
|
var db = dbm.getMainDatabase()
|
||||||
var df = base.getInstance().getAutowireCapableBeanFactory()
|
var bf = base.getInstance().getAutowireCapableBeanFactory()
|
||||||
}
|
}
|
||||||
return '§a返回结果: §r'+ eval(${JSON.stringify(code)});
|
return '§a返回结果: §r'+ eval(${JSON.stringify(code)});`)
|
||||||
`)
|
|
||||||
return this.task.callSyncMethod(() => tfunc.apply(this, params)) + ''
|
return this.task.callSyncMethod(() => tfunc.apply(this, params)) + ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
packages/plugins/src/MiaoProtocol.ts
Normal file
32
packages/plugins/src/MiaoProtocol.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/// <reference types="@ccms/types" />
|
||||||
|
|
||||||
|
import { task, server, constants } from "@ccms/api";
|
||||||
|
import { inject } from "@ccms/container";
|
||||||
|
import { plugin, interfaces, cmd } from "@ccms/plugin";
|
||||||
|
|
||||||
|
import http from '@ccms/common/dist/http'
|
||||||
|
import * as fs from '@ccms/common/dist/fs'
|
||||||
|
|
||||||
|
@plugin({ name: 'MiaoProtocol', prefix: 'MPTL', version: '1.0.0', author: 'MiaoWoo', servers: [constants.ServerType.Bukkit], source: __filename })
|
||||||
|
export class MiaoProtocol extends interfaces.Plugin {
|
||||||
|
@inject(server.Server)
|
||||||
|
private server: server.Server;
|
||||||
|
@inject(task.TaskManager)
|
||||||
|
private taskManager: task.TaskManager;
|
||||||
|
|
||||||
|
private pipeline: any
|
||||||
|
|
||||||
|
enable() {
|
||||||
|
let count = 0
|
||||||
|
let wait = this.taskManager.create(() => {
|
||||||
|
this.pipeline = this.server.getNettyPipeline()
|
||||||
|
if (this.pipeline) {
|
||||||
|
wait.cancel()
|
||||||
|
} else if (count++ > 30) {
|
||||||
|
wait.cancel()
|
||||||
|
this.logger.console('§cNetty通道注入失败 §4所有功能将无法使用!')
|
||||||
|
}
|
||||||
|
}).later(20).timer(40).submit()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
import { plugin as pluginApi, task, server } from '@ccms/api'
|
import { plugin as pluginApi, task, server } from '@ccms/api'
|
||||||
|
|
||||||
import { Translate } from '@ccms/i18n'
|
import { Translate } from '@ccms/i18n'
|
||||||
import { inject } from '@ccms/container';
|
import { inject, DefaultContainer as container } from '@ccms/container'
|
||||||
import { interfaces, plugin, cmd, tab } from '@ccms/plugin'
|
import { interfaces, plugin, cmd, tab } from '@ccms/plugin'
|
||||||
|
|
||||||
import * as fs from '@ccms/common/dist/fs'
|
import * as fs from '@ccms/common/dist/fs'
|
||||||
|
import * as reflect from '@ccms/common/dist/reflect'
|
||||||
import http from '@ccms/common/dist/http'
|
import http from '@ccms/common/dist/http'
|
||||||
|
|
||||||
let help = [
|
let help = [
|
||||||
@ -19,7 +20,7 @@ let help = [
|
|||||||
'§6/mpm §arun §e<JS代码> §6- §3运行JS代码',
|
'§6/mpm §arun §e<JS代码> §6- §3运行JS代码',
|
||||||
'§6/mpm §adeploy §e<插件名称> §6- §3发布插件',
|
'§6/mpm §adeploy §e<插件名称> §6- §3发布插件',
|
||||||
'§6/mpm §crestart §6- §4重启MiaoScript脚本引擎'
|
'§6/mpm §crestart §6- §4重启MiaoScript脚本引擎'
|
||||||
];
|
]
|
||||||
|
|
||||||
let langMap = {
|
let langMap = {
|
||||||
'main.command.not.exists': '§4未知的子命令: §c{command}',
|
'main.command.not.exists': '§4未知的子命令: §c{command}',
|
||||||
@ -53,20 +54,20 @@ let fallbackMap = langMap
|
|||||||
@plugin({ name: 'MiaoScriptPackageManager', prefix: 'PM', version: '1.0.1', author: 'MiaoWoo', source: __filename })
|
@plugin({ name: 'MiaoScriptPackageManager', prefix: 'PM', version: '1.0.1', author: 'MiaoWoo', source: __filename })
|
||||||
export class MiaoScriptPackageManager extends interfaces.Plugin {
|
export class MiaoScriptPackageManager extends interfaces.Plugin {
|
||||||
@inject(pluginApi.PluginManager)
|
@inject(pluginApi.PluginManager)
|
||||||
private pluginManager: pluginApi.PluginManager;
|
private pluginManager: pluginApi.PluginManager
|
||||||
@inject(task.TaskManager)
|
@inject(task.TaskManager)
|
||||||
private taskManager: task.TaskManager;
|
private taskManager: task.TaskManager
|
||||||
@inject(server.ServerType)
|
@inject(server.ServerType)
|
||||||
private serverType: string;
|
private serverType: string
|
||||||
@inject(server.Server)
|
@inject(server.Server)
|
||||||
private server: server.Server
|
private server: server.Server
|
||||||
@inject(pluginApi.PluginFolder)
|
@inject(pluginApi.PluginFolder)
|
||||||
private pluginFolder: string;
|
private pluginFolder: string
|
||||||
|
|
||||||
private packageCache: any[] = [];
|
private packageCache: any[] = [];
|
||||||
private packageNameCache: string[] = [];
|
private packageNameCache: string[] = [];
|
||||||
|
|
||||||
private translate: Translate;
|
private translate: Translate
|
||||||
|
|
||||||
load() {
|
load() {
|
||||||
this.translate = new Translate({
|
this.translate = new Translate({
|
||||||
@ -78,7 +79,7 @@ export class MiaoScriptPackageManager extends interfaces.Plugin {
|
|||||||
|
|
||||||
@cmd()
|
@cmd()
|
||||||
mpm(sender: any, command: string, args: string[]) {
|
mpm(sender: any, command: string, args: string[]) {
|
||||||
this.taskManager.create(() => this.main(sender, command, args)).async().submit();
|
this.taskManager.create(() => this.main(sender, command, args)).async().submit()
|
||||||
}
|
}
|
||||||
|
|
||||||
i18n(sender: any, name: string, params?: any) {
|
i18n(sender: any, name: string, params?: any) {
|
||||||
@ -90,64 +91,64 @@ export class MiaoScriptPackageManager extends interfaces.Plugin {
|
|||||||
if (!this[cmdKey]) {
|
if (!this[cmdKey]) {
|
||||||
this.i18n(sender, 'main.command.not.exists', { command: args[0] })
|
this.i18n(sender, 'main.command.not.exists', { command: args[0] })
|
||||||
this.i18n(sender, 'main.command.help.tip', { command })
|
this.i18n(sender, 'main.command.help.tip', { command })
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
args.shift()
|
args.shift()
|
||||||
this[cmdKey](sender, ...args);
|
this[cmdKey](sender, ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdhelp(sender: any) {
|
cmdhelp(sender: any) {
|
||||||
this.logger.sender(sender, help);
|
this.logger.sender(sender, help)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdload(sender: any, name: string) {
|
cmdload(sender: any, name: string) {
|
||||||
let pluginFile = fs.concat(__dirname + '', name);
|
let pluginFile = fs.concat(__dirname + '', name)
|
||||||
if (!fs.exists(pluginFile)) {
|
if (!fs.exists(pluginFile)) {
|
||||||
this.i18n(sender, 'plugin.not.exists', { name: `${name}(${pluginFile})` })
|
this.i18n(sender, 'plugin.not.exists', { name: `${name}(${pluginFile})` })
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.pluginManager.loadFromFile(fs.file(pluginFile));
|
this.pluginManager.loadFromFile(fs.file(pluginFile))
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdlist(sender: any, type: string = 'cloud') {
|
cmdlist(sender: any, type: string = 'cloud') {
|
||||||
if (type == "i" || type == "install") {
|
if (type == "i" || type == "install") {
|
||||||
this.i18n(sender, 'list.install.header')
|
this.i18n(sender, 'list.install.header')
|
||||||
this.pluginManager.getPlugins().forEach((plugin) => {
|
this.pluginManager.getPlugins().forEach((plugin) => {
|
||||||
this.i18n(sender, 'list.install.body', plugin.description);
|
this.i18n(sender, 'list.install.body', plugin.description)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.i18n(sender, 'list.header')
|
this.i18n(sender, 'list.header')
|
||||||
for (var pkgName in this.packageCache) {
|
for (var pkgName in this.packageCache) {
|
||||||
this.i18n(sender, 'list.body', this.packageCache[pkgName]);
|
this.i18n(sender, 'list.body', this.packageCache[pkgName])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdinstall(sender: any, name: string) {
|
cmdinstall(sender: any, name: string) {
|
||||||
if (!name) { return this.i18n(sender, 'plugin.name.empty') }
|
if (!name) { return this.i18n(sender, 'plugin.name.empty') }
|
||||||
this.download(sender, name);
|
this.download(sender, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdupdate(sender: any, name: string) {
|
cmdupdate(sender: any, name: string) {
|
||||||
if (name) {
|
if (name) {
|
||||||
this.update(sender, name);
|
this.update(sender, name)
|
||||||
} else {
|
} else {
|
||||||
this.updateRepo(sender)
|
this.updateRepo(sender)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdupgrade(sender: any, name: string) {
|
cmdupgrade(sender: any, name: string) {
|
||||||
if (!name) { return this.i18n(sender, 'upgrade.confirm'); }
|
if (!name) { return this.i18n(sender, 'upgrade.confirm') }
|
||||||
if (name == "comfirm") {
|
if (name == "comfirm") {
|
||||||
let enginePath = fs.path(fs.file(fs.concat(root, 'node_modules', '@ccms')))
|
let enginePath = fs.path(fs.file(fs.concat(root, 'node_modules', '@ccms')))
|
||||||
if (enginePath.startsWith(root)) {
|
if (enginePath.startsWith(root)) {
|
||||||
base.delete(enginePath);
|
base.delete(enginePath)
|
||||||
this.cmdrestart(sender);
|
this.cmdrestart(sender)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.checkPlugin(sender, name)) {
|
if (this.checkPlugin(sender, name)) {
|
||||||
this.update(sender, name);
|
this.update(sender, name)
|
||||||
this.pluginManager.reload(name);
|
this.pluginManager.reload(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +162,7 @@ export class MiaoScriptPackageManager extends interfaces.Plugin {
|
|||||||
cmdreload(sender: any, name: string) {
|
cmdreload(sender: any, name: string) {
|
||||||
name = name || this.description.name
|
name = name || this.description.name
|
||||||
if (this.checkPlugin(sender, name)) {
|
if (this.checkPlugin(sender, name)) {
|
||||||
this.pluginManager.reload(name);
|
this.pluginManager.reload(name)
|
||||||
this.i18n(sender, 'plugin.reload.finish', { name })
|
this.i18n(sender, 'plugin.reload.finish', { name })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,33 +185,58 @@ export class MiaoScriptPackageManager extends interfaces.Plugin {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.logger.sender(sender, '§6Reloading §3MiaoScript Engine...');
|
this.logger.sender(sender, '§6Reloading §3MiaoScript Engine...')
|
||||||
ScriptEngineContextHolder.disableEngine();
|
ScriptEngineContextHolder.disableEngine()
|
||||||
Packages.java.lang.System.gc();
|
Packages.java.lang.System.gc()
|
||||||
ScriptEngineContextHolder.enableEngine();
|
ScriptEngineContextHolder.enableEngine()
|
||||||
this.logger.sender(sender, '§3MiaoScript Engine §6Reload §aSuccessful...');
|
this.logger.sender(sender, '§3MiaoScript Engine §6Reload §aSuccessful...')
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
this.logger.sender(sender, "§3MiaoScript Engine §6Reload §cError! ERR: " + ex);
|
this.logger.sender(sender, "§3MiaoScript Engine §6Reload §cError! ERR: " + ex)
|
||||||
this.logger.sender(sender, this.logger.stack(ex));
|
this.logger.sender(sender, this.logger.stack(ex))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdrun(sender: any, ...args: any[]) {
|
cmdrun(sender: any, ...args: any[]) {
|
||||||
try {
|
try {
|
||||||
let script = args.join(' ');
|
let script = args.join(' ')
|
||||||
this.i18n(sender, 'run.script', { script })
|
this.i18n(sender, 'run.script', { script })
|
||||||
let result = eval(script);
|
let result = this.runCode(script, sender)
|
||||||
this.i18n(sender, 'run.result', { result: result == undefined ? this.translate.translate('run.noresult') : result + '' })
|
this.i18n(sender, 'run.result', { result: result == undefined ? this.translate.translate('run.noresult') : result + '' })
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
this.logger.sender(sender, this.logger.stack(ex));
|
this.logger.sender(sender, this.logger.stack(ex))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private runCode(code: string, sender: any) {
|
||||||
|
let paramNames = [
|
||||||
|
'sender',
|
||||||
|
'reflect',
|
||||||
|
'container',
|
||||||
|
'pluginManager'
|
||||||
|
]
|
||||||
|
let params = [
|
||||||
|
sender,
|
||||||
|
reflect,
|
||||||
|
container,
|
||||||
|
this.pluginManager
|
||||||
|
]
|
||||||
|
let tfunc = new Function(
|
||||||
|
...paramNames,
|
||||||
|
`var api = require('@ccms/api');
|
||||||
|
if (this.serverType == "spring") {
|
||||||
|
var dbm = container.get(api.database.DataBaseManager)
|
||||||
|
var db = dbm.getMainDatabase()
|
||||||
|
var df = base.getInstance().getAutowireCapableBeanFactory()
|
||||||
|
}
|
||||||
|
return '§a返回结果: §r'+ eval(${JSON.stringify(code)});`)
|
||||||
|
return tfunc.apply(this, params) + ''
|
||||||
|
}
|
||||||
|
|
||||||
cmddeploy(sender: any, name: any) {
|
cmddeploy(sender: any, name: any) {
|
||||||
if (!process.env.AccessToken) { return this.i18n(sender, 'deploy.token.not.exists') }
|
if (!process.env.AccessToken) { return this.i18n(sender, 'deploy.token.not.exists') }
|
||||||
this.taskManager.create(() => {
|
this.taskManager.create(() => {
|
||||||
if (this.checkPlugin(sender, name)) {
|
if (this.checkPlugin(sender, name)) {
|
||||||
let plugin: pluginApi.Plugin = this.pluginManager.getPlugins().get(name);
|
let plugin: pluginApi.Plugin = this.pluginManager.getPlugins().get(name)
|
||||||
let result = http.post("http://ms.yumc.pw/api/plugin/deploy?access_token=" + process.env.AccessToken, {
|
let result = http.post("http://ms.yumc.pw/api/plugin/deploy?access_token=" + process.env.AccessToken, {
|
||||||
name,
|
name,
|
||||||
author: plugin.description.author,
|
author: plugin.description.author,
|
||||||
@ -224,7 +250,7 @@ export class MiaoScriptPackageManager extends interfaces.Plugin {
|
|||||||
|
|
||||||
update(sender: any, name: string) {
|
update(sender: any, name: string) {
|
||||||
if (this.checkCloudPlugin(sender, name)) {
|
if (this.checkCloudPlugin(sender, name)) {
|
||||||
this.download(sender, name, true);
|
this.download(sender, name, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,25 +262,25 @@ export class MiaoScriptPackageManager extends interfaces.Plugin {
|
|||||||
case "list":
|
case "list":
|
||||||
return ["install", "cloud"]
|
return ["install", "cloud"]
|
||||||
case "install":
|
case "install":
|
||||||
return this.packageNameCache;
|
return this.packageNameCache
|
||||||
case "update":
|
case "update":
|
||||||
case "upgrade":
|
case "upgrade":
|
||||||
case "load":
|
case "load":
|
||||||
case "unload":
|
case "unload":
|
||||||
case "reload":
|
case "reload":
|
||||||
case "deploy":
|
case "deploy":
|
||||||
return [...this.pluginManager.getPlugins().keys()];
|
return [...this.pluginManager.getPlugins().keys()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRepo(sender: any) {
|
updateRepo(sender: any) {
|
||||||
this.taskManager.create(() => {
|
this.taskManager.create(() => {
|
||||||
let result = http.get('http://ms.yumc.pw/api/plugin/list');
|
let result = http.get('http://ms.yumc.pw/api/plugin/list')
|
||||||
for (const pl of result.data) { this.packageCache[pl.name] = pl; }
|
for (const pl of result.data) { this.packageCache[pl.name] = pl }
|
||||||
this.packageNameCache = Object.keys(this.packageCache);
|
this.packageNameCache = Object.keys(this.packageCache)
|
||||||
this.i18n(sender, 'cloud.update.finish', { length: this.packageNameCache.length })
|
this.i18n(sender, 'cloud.update.finish', { length: this.packageNameCache.length })
|
||||||
}).async().submit();
|
}).async().submit()
|
||||||
}
|
}
|
||||||
|
|
||||||
download(sender: any, name: string, update: boolean = false) {
|
download(sender: any, name: string, update: boolean = false) {
|
||||||
|
@ -2,58 +2,30 @@
|
|||||||
/// <reference types="@ccms/types/dist/typings/tomcat/index" />
|
/// <reference types="@ccms/types/dist/typings/tomcat/index" />
|
||||||
/// <reference types="@ccms/types/dist/typings/spring/index" />
|
/// <reference types="@ccms/types/dist/typings/spring/index" />
|
||||||
|
|
||||||
import { constants, database, plugin } from "@ccms/api"
|
import { constants, database, plugin, web } from "@ccms/api"
|
||||||
import { inject, ContainerInstance, Container, JSClass } from "@ccms/container"
|
import { inject, ContainerInstance, Container } from "@ccms/container"
|
||||||
import { JSPlugin, interfaces, cmd } from "@ccms/plugin"
|
import { JSPlugin, interfaces, cmd } from "@ccms/plugin"
|
||||||
import { DataBase, DataBaseManager } from '@ccms/database'
|
import { DataBase, DataBaseManager } from '@ccms/database'
|
||||||
|
import { Server, Context, RequestHandler } from '@ccms/web'
|
||||||
|
|
||||||
import * as fs from '@ccms/common/dist/fs'
|
import * as fs from '@ccms/common/dist/fs'
|
||||||
import * as reflect from '@ccms/common/dist/reflect'
|
import * as reflect from '@ccms/common/dist/reflect'
|
||||||
import * as querystring from 'querystring'
|
|
||||||
|
|
||||||
const WebProxyBeanName = 'webServerProxy'
|
@JSPlugin({ name: 'MiaoSpring', prefix: 'MSpring', version: '1.0.1', author: 'MiaoWoo', servers: [constants.ServerType.Spring], source: __filename })
|
||||||
const FilterProxyBeanName = 'webFilterProxy'
|
|
||||||
type RequestHandler = (ctx: Context) => any
|
|
||||||
interface InterceptorAdapter {
|
|
||||||
name: string
|
|
||||||
preHandle?(ctx: Context): void
|
|
||||||
postHandle?(ctx: Context): void
|
|
||||||
}
|
|
||||||
|
|
||||||
type RequestHeader = { [key: string]: string | string[] }
|
|
||||||
type RequestParams = { [key: string]: string | string[] }
|
|
||||||
|
|
||||||
interface Context {
|
|
||||||
request?: javax.servlet.http.HttpServletRequest
|
|
||||||
response?: javax.servlet.http.HttpServletResponse
|
|
||||||
header?: RequestHeader
|
|
||||||
url?: string
|
|
||||||
params?: RequestParams
|
|
||||||
body?: any
|
|
||||||
result?: any
|
|
||||||
}
|
|
||||||
|
|
||||||
@JSPlugin({ name: 'MiaoSpring', prefix: 'MSpring', version: '1.0.1', author: 'MiaoWoo', servers: [constants.ServerType.Bukkit], source: __filename })
|
|
||||||
export class MiaoSpring extends interfaces.Plugin {
|
export class MiaoSpring extends interfaces.Plugin {
|
||||||
@JSClass('pw.yumc.MiaoScript.web.WebServerProxy')
|
|
||||||
private WebServerProxy: any
|
|
||||||
@JSClass('pw.yumc.MiaoScript.web.WebFilterProxy')
|
|
||||||
private WebFilterProxy: any
|
|
||||||
private StreamUtils = org.springframework.util.StreamUtils
|
|
||||||
private ResponseEntity = org.springframework.http.ResponseEntity
|
|
||||||
|
|
||||||
@inject(ContainerInstance)
|
@inject(ContainerInstance)
|
||||||
private container: Container
|
private container: Container
|
||||||
@inject(plugin.PluginInstance)
|
|
||||||
private context: any
|
|
||||||
@inject(plugin.PluginManager)
|
@inject(plugin.PluginManager)
|
||||||
private pluginManager: plugin.PluginManager
|
private pluginManager: plugin.PluginManager
|
||||||
@inject(database.DataBaseManager)
|
@inject(database.DataBaseManager)
|
||||||
private databaseManager: DataBaseManager
|
private databaseManager: DataBaseManager
|
||||||
|
@inject(web.Server)
|
||||||
|
private webServer: Server
|
||||||
|
|
||||||
|
private ResponseEntity = org.springframework.http.ResponseEntity
|
||||||
|
|
||||||
private beanFactory: any
|
|
||||||
private mainDatabase: DataBase
|
private mainDatabase: DataBase
|
||||||
private interceptors: InterceptorAdapter[] = []
|
private mappings: Set<string>
|
||||||
private requestMapping: { [key: string]: RequestHandler } = {}
|
|
||||||
|
|
||||||
@cmd()
|
@cmd()
|
||||||
mspring(sender: any) {
|
mspring(sender: any) {
|
||||||
@ -62,144 +34,24 @@ export class MiaoSpring extends interfaces.Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
load() {
|
load() {
|
||||||
this.beanFactory = this.context.getAutowireCapableBeanFactory()
|
|
||||||
this.mainDatabase = this.databaseManager.getMainDatabase()
|
this.mainDatabase = this.databaseManager.getMainDatabase()
|
||||||
|
this.mappings = new Set()
|
||||||
}
|
}
|
||||||
|
|
||||||
enable() {
|
enable() {
|
||||||
this.registryWebBean()
|
|
||||||
this.registryDefault()
|
this.registryDefault()
|
||||||
this.registryPages()
|
this.registryPages()
|
||||||
this.registryDatabase()
|
this.registryDatabase()
|
||||||
}
|
}
|
||||||
|
|
||||||
registryWebBean() {
|
|
||||||
try { this.beanFactory.destroySingleton(FilterProxyBeanName); this.beanFactory.destroySingleton(WebProxyBeanName) } catch (ex) { }
|
|
||||||
var WebFilterProxyNashorn = Java.extend(this.WebFilterProxy, {
|
|
||||||
doFilter: (servletRequest: javax.servlet.http.HttpServletRequest, servletResponse: javax.servlet.http.HttpServletResponse, filterChain: javax.servlet.FilterChain) => {
|
|
||||||
console.log('WebFilterProxyNashorn', 'doFilter', servletRequest, servletResponse)
|
|
||||||
filterChain.doFilter(servletRequest, servletResponse)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.beanFactory.registerSingleton(FilterProxyBeanName, new WebFilterProxyNashorn())
|
|
||||||
var WebServerProxyNashorn = Java.extend(this.WebServerProxy, {
|
|
||||||
process: (req: javax.servlet.http.HttpServletRequest, resp: javax.servlet.http.HttpServletResponse) => {
|
|
||||||
let ctx: Context = { request: req, response: resp }
|
|
||||||
ctx.url = req.getRequestURI()
|
|
||||||
// @ts-ignore
|
|
||||||
ctx.header = { __noSuchProperty__: (name: string) => req.getHeader(name) + '' }
|
|
||||||
if (req.getQueryString()) {
|
|
||||||
ctx.url += `?${req.getQueryString()}`
|
|
||||||
ctx.params = querystring.parse(req.getQueryString())
|
|
||||||
}
|
|
||||||
if (req.getMethod() == "POST") {
|
|
||||||
ctx.body = this.StreamUtils.copyToString(req.getInputStream(), java.nio.charset.StandardCharsets.UTF_8)
|
|
||||||
if ((ctx.header['Content-Type'] || '').includes('application/json')) {
|
|
||||||
try {
|
|
||||||
ctx.body = JSON.parse(ctx.body)
|
|
||||||
} catch (error) {
|
|
||||||
return {
|
|
||||||
status: 500,
|
|
||||||
msg: `parse json body error: ${error}`,
|
|
||||||
path: ctx.url,
|
|
||||||
error: console.stack(error, false),
|
|
||||||
timestamp: Date.now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let result = this.process(ctx)
|
|
||||||
result?.status && resp.setStatus(result.status)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.beanFactory.registerSingleton(WebProxyBeanName, new WebServerProxyNashorn())
|
|
||||||
}
|
|
||||||
|
|
||||||
private process(ctx: Context) {
|
|
||||||
let startTime = Date.now()
|
|
||||||
for (const interceptor of this.interceptors) {
|
|
||||||
if (interceptor.preHandle) {
|
|
||||||
try {
|
|
||||||
let startTime = Date.now()
|
|
||||||
ctx.result = interceptor.preHandle(ctx)
|
|
||||||
let preHandleTime = Date.now() - startTime
|
|
||||||
if (preHandleTime > 20) {
|
|
||||||
console.debug(`[WARN] Interceptor ${interceptor.name} preHandle cost time ${preHandleTime}ms!`)
|
|
||||||
}
|
|
||||||
if (ctx.result) { return ctx.result }
|
|
||||||
} catch (error) {
|
|
||||||
console.ex(error)
|
|
||||||
return {
|
|
||||||
status: 500,
|
|
||||||
msg: `Interceptor ${interceptor.name} preHandle error: ${error}`,
|
|
||||||
path: ctx.url,
|
|
||||||
error: console.stack(error, false),
|
|
||||||
timestamp: Date.now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let preHandleTime = Date.now() - startTime; startTime = Date.now()
|
|
||||||
ctx.result = this.execRequestHandle(ctx)
|
|
||||||
let execTime = Date.now() - startTime; startTime = Date.now()
|
|
||||||
for (const interceptor of this.interceptors) {
|
|
||||||
if (interceptor.postHandle) {
|
|
||||||
try {
|
|
||||||
ctx.result = interceptor.postHandle(ctx)
|
|
||||||
} catch (error) {
|
|
||||||
return {
|
|
||||||
status: 500,
|
|
||||||
msg: `Interceptor ${interceptor.name} postHandle error: ${error}`,
|
|
||||||
path: ctx.url,
|
|
||||||
error: console.stack(error, false),
|
|
||||||
timestamp: Date.now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let postHandleTime = Date.now() - startTime
|
|
||||||
console.debug(`
|
|
||||||
===================== MiaoSpring =====================
|
|
||||||
Request URL : ${ctx.url}
|
|
||||||
preHandle Time : ${preHandleTime}ms
|
|
||||||
exec Time : ${execTime}ms
|
|
||||||
Response Body : ${JSON.stringify(Java.asJSONCompatible(ctx.result))}
|
|
||||||
postHandle Time : ${postHandleTime}ms
|
|
||||||
Handle Time : ${preHandleTime + execTime + postHandleTime}ms
|
|
||||||
======================================================`)
|
|
||||||
return ctx.result
|
|
||||||
}
|
|
||||||
|
|
||||||
private execRequestHandle(ctx: Context) {
|
|
||||||
if (!this.requestMapping[ctx.request.getRequestURI()]) {
|
|
||||||
return {
|
|
||||||
status: 404,
|
|
||||||
msg: "requestMapping Not Found!",
|
|
||||||
path: ctx.url,
|
|
||||||
timestamp: Date.now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return this.requestMapping[ctx.request.getRequestURI()](ctx)
|
|
||||||
} catch (error) {
|
|
||||||
return {
|
|
||||||
status: 500,
|
|
||||||
msg: '' + error,
|
|
||||||
path: ctx.url,
|
|
||||||
error: console.stack(error, false),
|
|
||||||
timestamp: Date.now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registryMapping(path: string, handler: RequestHandler) {
|
registryMapping(path: string, handler: RequestHandler) {
|
||||||
this.requestMapping[path] = handler
|
this.mappings.add(path)
|
||||||
|
this.webServer.registryMapping(path, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
registryDefault() {
|
registryDefault() {
|
||||||
const foundMap = ["/node_modules/amis/sdk/sdk.js", 'https://houtai.baidu.com/v2/jssdk', "/node_modules/amis/sdk/sdk.css", 'https://houtai.baidu.com/v2/csssdk']
|
const foundMap = ["/node_modules/amis/sdk/sdk.js", 'https://houtai.baidu.com/v2/jssdk', "/node_modules/amis/sdk/sdk.css", 'https://houtai.baidu.com/v2/csssdk']
|
||||||
this.interceptors.push({
|
this.webServer.registryInterceptor({
|
||||||
name: 'RedirectHandle',
|
name: 'RedirectHandle',
|
||||||
preHandle: (ctx: Context) => {
|
preHandle: (ctx: Context) => {
|
||||||
const index = foundMap.indexOf(ctx.request.getRequestURI())
|
const index = foundMap.indexOf(ctx.request.getRequestURI())
|
||||||
@ -208,7 +60,7 @@ Handle Time : ${preHandleTime + execTime + postHandleTime}ms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.interceptors.push({
|
this.webServer.registryInterceptor({
|
||||||
name: 'StaticHandle',
|
name: 'StaticHandle',
|
||||||
preHandle: (ctx: Context) => {
|
preHandle: (ctx: Context) => {
|
||||||
let type = ctx.header['Accept'] || ''
|
let type = ctx.header['Accept'] || ''
|
||||||
@ -225,27 +77,27 @@ Handle Time : ${preHandleTime + execTime + postHandleTime}ms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.registryMapping('/api/eval', (ctx: Context) => {
|
this.webServer.registryMapping('/api/eval', (ctx: Context) => {
|
||||||
try {
|
try {
|
||||||
return { status: 200, data: this.runCode(ctx.body + ''), msg: '代码执行成功!' }
|
return { status: 200, data: this.runCode(ctx.body + ''), msg: '代码执行成功!' }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { status: 500, data: console.stack(error, false), msg: '代码执行异常!' }
|
return { status: 500, data: console.stack(error, false), msg: '代码执行异常!' }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.registryMapping('/api/plugin/list', () => {
|
this.webServer.registryMapping('/api/plugin/list', () => {
|
||||||
return { status: 200, data: [...this.pluginManager.getPlugins().values()].map((plugin) => plugin.description), msg: '插件列表获取成功!' }
|
return { status: 200, data: [...this.pluginManager.getPlugins().values()].map((plugin) => plugin.description), msg: '插件列表获取成功!' }
|
||||||
})
|
})
|
||||||
this.registryMapping('/api/plugin/update', (ctx: Context) => {
|
this.webServer.registryMapping('/api/plugin/update', (ctx: Context) => {
|
||||||
if (!ctx.params.name) { return { status: 400, msg: '插件名称不得为空!' } }
|
if (!ctx.params.name) { return { status: 400, msg: '插件名称不得为空!' } }
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private registryPages() {
|
private registryPages() {
|
||||||
this.registryMapping('/api/page/list', () => {
|
this.webServer.registryMapping('/api/page/list', () => {
|
||||||
return { status: 0, data: { rows: this.mainDatabase.query('SELECT `id`, `type`, `name`, `content` FROM `pages` WHERE `deleted` = 0') } }
|
return { status: 0, data: { rows: this.mainDatabase.query('SELECT `id`, `type`, `name`, `content` FROM `pages` WHERE `deleted` = 0') } }
|
||||||
})
|
})
|
||||||
this.registryMapping('/api/page/get', (ctx: Context) => {
|
this.webServer.registryMapping('/api/page/get', (ctx: Context) => {
|
||||||
let name = decodeURIComponent(`${ctx.params.name}`)
|
let name = decodeURIComponent(`${ctx.params.name}`)
|
||||||
let varable = undefined
|
let varable = undefined
|
||||||
if (!name) { return { status: 400, msg: '名称不能为空!' } }
|
if (!name) { return { status: 400, msg: '名称不能为空!' } }
|
||||||
@ -265,20 +117,20 @@ Handle Time : ${preHandleTime + execTime + postHandleTime}ms
|
|||||||
}
|
}
|
||||||
return { status: 0, data: JSON.parse(content) }
|
return { status: 0, data: JSON.parse(content) }
|
||||||
})
|
})
|
||||||
this.registryMapping('/api/page/add', (ctx: Context) => {
|
this.webServer.registryMapping('/api/page/add', (ctx: Context) => {
|
||||||
let body = ctx.body
|
let body = ctx.body
|
||||||
if (typeof body.content !== "string") { body.content = JSON.stringify(body.content) }
|
if (typeof body.content !== "string") { body.content = JSON.stringify(body.content) }
|
||||||
this.mainDatabase.update("INSERT INTO `pages`(`type`, `name`, `content`) VALUES (?, ?, ?)", body.type || 1, body.name, body.content)
|
this.mainDatabase.update("INSERT INTO `pages`(`type`, `name`, `content`) VALUES (?, ?, ?)", body.type || 1, body.name, body.content)
|
||||||
return { status: 0, msg: `${body.name} 新增成功!` }
|
return { status: 0, msg: `${body.name} 新增成功!` }
|
||||||
})
|
})
|
||||||
this.registryMapping('/api/page/update', (ctx: Context) => {
|
this.webServer.registryMapping('/api/page/update', (ctx: Context) => {
|
||||||
if (!ctx.params.id) { return { status: 400, msg: 'ID 不能为空!' } }
|
if (!ctx.params.id) { return { status: 400, msg: 'ID 不能为空!' } }
|
||||||
const body = ctx.body
|
const body = ctx.body
|
||||||
if (typeof body.content !== "string") { body.content = JSON.stringify(body.content) }
|
if (typeof body.content !== "string") { body.content = JSON.stringify(body.content) }
|
||||||
this.mainDatabase.update("UPDATE `pages` SET `name` = ?, `content` = ? WHERE id = ?", body.name, body.content, ctx.params.id)
|
this.mainDatabase.update("UPDATE `pages` SET `name` = ?, `content` = ? WHERE id = ?", body.name, body.content, ctx.params.id)
|
||||||
return { status: 0, msg: `${body.name} 更新成功!` }
|
return { status: 0, msg: `${body.name} 更新成功!` }
|
||||||
})
|
})
|
||||||
this.registryMapping('/api/page/delete', (ctx: Context) => {
|
this.webServer.registryMapping('/api/page/delete', (ctx: Context) => {
|
||||||
if (!ctx.params.name) { return { status: 400, msg: '页面 名称 不能为空!' } }
|
if (!ctx.params.name) { return { status: 400, msg: '页面 名称 不能为空!' } }
|
||||||
this.mainDatabase.update("UPDATE `pages` SET `name` = CONCAT(name, '_deleted'), deleted = 1 WHERE name = ?", ctx.params.name)
|
this.mainDatabase.update("UPDATE `pages` SET `name` = CONCAT(name, '_deleted'), deleted = 1 WHERE name = ?", ctx.params.name)
|
||||||
return { status: 0, msg: `${ctx.params.name} 删除成功!` }
|
return { status: 0, msg: `${ctx.params.name} 删除成功!` }
|
||||||
@ -288,17 +140,17 @@ Handle Time : ${preHandleTime + execTime + postHandleTime}ms
|
|||||||
private configTable = "config"
|
private configTable = "config"
|
||||||
|
|
||||||
private registryDatabase() {
|
private registryDatabase() {
|
||||||
this.registryMapping('/api/config/list', (ctx: Context) => {
|
this.webServer.registryMapping('/api/config/list', (ctx: Context) => {
|
||||||
return { status: 0, data: this.mainDatabase.query('SELECT id, name, label, url, driver, username, password FROM `' + this.configTable + '` WHERE deleted = 0 AND type = ?', ctx.params.type || 0) }
|
return { status: 0, data: this.mainDatabase.query('SELECT id, name, label, url, driver, username, password FROM `' + this.configTable + '` WHERE deleted = 0 AND type = ?', ctx.params.type || 0) }
|
||||||
})
|
})
|
||||||
this.registryMapping('/api/config/get', (ctx: Context) => {
|
this.webServer.registryMapping('/api/config/get', (ctx: Context) => {
|
||||||
let name = ctx.params.name
|
let name = ctx.params.name
|
||||||
if (!name) { return { status: 400, msg: '名称不能为空!' } }
|
if (!name) { return { status: 400, msg: '名称不能为空!' } }
|
||||||
let result = this.mainDatabase.query('SELECT id, name, label, url, driver, username, password FROM `' + this.configTable + '` WHERE `name` = ?', name)
|
let result = this.mainDatabase.query('SELECT id, name, label, url, driver, username, password FROM `' + this.configTable + '` WHERE `name` = ?', name)
|
||||||
if (!result.length) { return { status: 404, msg: `配置 ${name} 不存在!` } }
|
if (!result.length) { return { status: 404, msg: `配置 ${name} 不存在!` } }
|
||||||
return { status: 0, data: result[0] }
|
return { status: 0, data: result[0] }
|
||||||
})
|
})
|
||||||
this.registryMapping('/api/config/add', (ctx: Context) => {
|
this.webServer.registryMapping('/api/config/add', (ctx: Context) => {
|
||||||
let body = ctx.body
|
let body = ctx.body
|
||||||
if (!body.name) { return { status: 400, msg: '名称不能为空!' } }
|
if (!body.name) { return { status: 400, msg: '名称不能为空!' } }
|
||||||
this.mainDatabase.update(
|
this.mainDatabase.update(
|
||||||
@ -307,7 +159,7 @@ Handle Time : ${preHandleTime + execTime + postHandleTime}ms
|
|||||||
)
|
)
|
||||||
return { status: 0, msg: `配置 ${body.name} 新增成功!` }
|
return { status: 0, msg: `配置 ${body.name} 新增成功!` }
|
||||||
})
|
})
|
||||||
this.registryMapping('/api/config/update', (ctx: Context) => {
|
this.webServer.registryMapping('/api/config/update', (ctx: Context) => {
|
||||||
if (!ctx.params.id) { return { status: 400, msg: 'ID 不能为空!' } }
|
if (!ctx.params.id) { return { status: 400, msg: 'ID 不能为空!' } }
|
||||||
let body = ctx.body
|
let body = ctx.body
|
||||||
this.mainDatabase.update(
|
this.mainDatabase.update(
|
||||||
@ -327,7 +179,6 @@ Handle Time : ${preHandleTime + execTime + postHandleTime}ms
|
|||||||
'pluginManager'
|
'pluginManager'
|
||||||
]
|
]
|
||||||
let params = [
|
let params = [
|
||||||
this.beanFactory,
|
|
||||||
this.mainDatabase,
|
this.mainDatabase,
|
||||||
reflect,
|
reflect,
|
||||||
this.container,
|
this.container,
|
||||||
@ -341,7 +192,6 @@ return eval(${JSON.stringify(code)});`)
|
|||||||
}
|
}
|
||||||
|
|
||||||
disable() {
|
disable() {
|
||||||
Object.keys(this.requestMapping).forEach((r) => delete this.requestMapping[r])
|
Object.keys(this.mappings).forEach((r) => this.webServer.unregistryMapping(r))
|
||||||
this.beanFactory.destroySingleton(WebProxyBeanName)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
181
packages/plugins/src/SearchRanking.ts
Normal file
181
packages/plugins/src/SearchRanking.ts
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/// <reference types="@ccms/types/dist/typings/rabbitmq" />
|
||||||
|
/// <reference types="@ccms/types/dist/typings/spring/amqp" />
|
||||||
|
|
||||||
|
import { constants, plugin as pluginApi, amqp, server, web } from '@ccms/api'
|
||||||
|
import { plugin, interfaces, cmd } from '@ccms/plugin'
|
||||||
|
import { AmqpAdmin, ConnectionFactoryAdapter, AmqpManager } from '@ccms/amqp'
|
||||||
|
import { inject, Autowired } from '@ccms/container'
|
||||||
|
import { Server } from '@ccms/web'
|
||||||
|
|
||||||
|
@plugin({ name: SearchRanking.name, version: SearchRanking.version, author: SearchRanking.author, servers: SearchRanking.servers, source: __filename })
|
||||||
|
export class SearchRanking extends interfaces.Plugin {
|
||||||
|
public static version = '1.0.0'
|
||||||
|
public static author = 'MiaoWoo'
|
||||||
|
public static servers = [constants.ServerType.Spring]
|
||||||
|
|
||||||
|
@inject(pluginApi.PluginManager)
|
||||||
|
private pluginManager: pluginApi.PluginManager
|
||||||
|
@inject(amqp.Manager)
|
||||||
|
private amqpManager: AmqpManager
|
||||||
|
@inject(server.Server)
|
||||||
|
private Server: server.Server
|
||||||
|
@inject(web.Server)
|
||||||
|
private webServer: Server
|
||||||
|
|
||||||
|
@Autowired()
|
||||||
|
private mongoTemplate: any
|
||||||
|
@Autowired()
|
||||||
|
private redisTemplate: any
|
||||||
|
|
||||||
|
private amqpAdmin: AmqpAdmin
|
||||||
|
private listener: org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer
|
||||||
|
|
||||||
|
private readonly exchangeName = 'search.ranking'
|
||||||
|
private readonly queueName = 'search.ranking'
|
||||||
|
private readonly routerKey = 'search.ranking'
|
||||||
|
|
||||||
|
load() {
|
||||||
|
let connection = new ConnectionFactoryAdapter({
|
||||||
|
url: 'amqp://rabbitmq.c.sixi.com:5672',
|
||||||
|
username: 'root',
|
||||||
|
password: 'SixiMQ2018@'
|
||||||
|
})
|
||||||
|
let template = this.amqpManager.createTemplate(connection)
|
||||||
|
this.amqpAdmin = this.amqpManager.createAdmin(template)
|
||||||
|
}
|
||||||
|
|
||||||
|
enable() {
|
||||||
|
this.webServer.registryMapping('/api/search', (ctx) => {
|
||||||
|
if (!ctx.params.keyword) { return { status: 400, msg: '查询关键词不得为空!' } }
|
||||||
|
let keyword = ctx.params.keyword + ''
|
||||||
|
let type = ctx.params.type == 'sale' ? 'sale' : 'normal'
|
||||||
|
let time = parseInt(ctx.params.time + '') || 60 * 60 * 24 * 15
|
||||||
|
return this.cacheAndSearch(keyword, type as any, time * 1000)
|
||||||
|
})
|
||||||
|
this.webServer.registryMapping('/api/search/ranking', (ctx) => {
|
||||||
|
if (!ctx.params.keyword || !ctx.params.shopName) { return { status: 400, msg: '查询关键词不得为空!' } }
|
||||||
|
let keyword = ctx.params.keyword + ''
|
||||||
|
let shopName = ctx.params.shopName + ''
|
||||||
|
let type = ctx.params.type == 'sale' ? 'sale' : 'normal'
|
||||||
|
let time = parseInt(ctx.params.time + '') || 60 * 60 * 24 * 15
|
||||||
|
return this.sendSearchRankingCmd(keyword, shopName, type as any, time * 1000)
|
||||||
|
})
|
||||||
|
this.amqpAdmin.declareQueueAndBindExchange(this.queueName, this.exchangeName, this.routerKey)
|
||||||
|
this.amqpAdmin.declareBinding(this.queueName, 'client.topic.exchange', `cmd_res.${this.routerKey}`)
|
||||||
|
this.listener = this.amqpAdmin.createContainer<string>(this.queueName, (content, message, channel) => {
|
||||||
|
let searchResult = JSON.parse(content)
|
||||||
|
this.redisTemplate.opsForValue().set(searchResult.reqData.cacheKey, searchResult)
|
||||||
|
this.logger.sender(this.Server.getConsoleSender(), `§6查询任务完成! §b关键词: §r${searchResult.reqData.keywords}`)
|
||||||
|
})
|
||||||
|
this.listener.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
disable() {
|
||||||
|
this.listener.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
@cmd()
|
||||||
|
sr(sender: any, cmd: string, args: string[]) {
|
||||||
|
let cmdKey = 'cmd' + (args[0] || 'help')
|
||||||
|
if (!this[cmdKey]) {
|
||||||
|
this.logger.sender(sender, `§4子命令 ${args[0]} 不存在!`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
args.shift()
|
||||||
|
this[cmdKey](sender, ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdrun(sender: any, ...args: string[]) {
|
||||||
|
sender.sendMessage(eval(args.join(' ')))
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdreload() {
|
||||||
|
this.pluginManager.reload(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdsend(sender: any, ...args: string[]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdsearch(sender: any, keyword: string, type: "sale" | "normal" = "sale", time: number) {
|
||||||
|
this.logger.sender(sender, this.cacheAndSearch(keyword, type, time)?.msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
private cacheAndSearch(keyword: string, type: string = "sale", time: number = 15 * 24 * 60 * 60 * 1000) {
|
||||||
|
let cacheKey = this.getCacheKey(keyword, type)
|
||||||
|
if (this.redisTemplate.hasKey(cacheKey)) {
|
||||||
|
let lastSearchTime = this.redisTemplate.opsForValue().get(cacheKey)
|
||||||
|
if (Date.now() - lastSearchTime > time) {
|
||||||
|
return this.createKeyworkSearch(keyword, type)
|
||||||
|
}
|
||||||
|
let lastSearchKey = this.getResultCacheKey(keyword, type, lastSearchTime)
|
||||||
|
if (!this.redisTemplate.hasKey(lastSearchKey)) {
|
||||||
|
return { status: 202, msg: `关键词: ${keyword} 排名类型: ${type} 缓存Key: ${lastSearchKey} 查询任务尚未完成...` }
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
status: 200,
|
||||||
|
msg: `关键词: ${keyword} 排名类型: ${type} 查询时间: ${new Date(lastSearchTime).toLocaleString()} 查询已完成!`,
|
||||||
|
data: this.redisTemplate.opsForValue().get(lastSearchKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.createKeyworkSearch(keyword, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
private createKeyworkSearch(keyword: string, type: string) {
|
||||||
|
let cacheDate = Date.now()
|
||||||
|
this.redisTemplate.opsForValue().set(this.getCacheKey(keyword, type), cacheDate)
|
||||||
|
this.sendSearchCmd(keyword, type, cacheDate)
|
||||||
|
return { status: 201, msg: `关键词: ${keyword} 排名类型: ${type} 查询任务以创建...`, createTime: cacheDate }
|
||||||
|
}
|
||||||
|
|
||||||
|
private createRankingSearch(keyword: string, shopName: string, type: string) {
|
||||||
|
let cacheDate = Date.now()
|
||||||
|
this.redisTemplate.opsForValue().set(this.getCacheKey(keyword, type), cacheDate)
|
||||||
|
this.sendSearchRankingCmd(keyword, shopName, type, cacheDate)
|
||||||
|
return { status: 201, msg: `关键词: ${keyword} 店铺名称: ${shopName} 排名类型: ${type} 查询任务以创建...`, createTime: cacheDate }
|
||||||
|
}
|
||||||
|
|
||||||
|
private sendSearchCmd(keywords: string, type: string, dateCache: number) {
|
||||||
|
this.amqpAdmin.getTemplate().convertAndSend('client.topic.exchange', 'cmd_req', {
|
||||||
|
cmd: 'scout._1688Search',
|
||||||
|
data: {
|
||||||
|
keywords: keywords,
|
||||||
|
parameter: type == "sale" ? {
|
||||||
|
descendOrder: true,
|
||||||
|
sortType: 'va_rmdarkgmv30rt',
|
||||||
|
button_click: 'top'
|
||||||
|
} : {},
|
||||||
|
cacheKey: this.getResultCacheKey(keywords, type, dateCache)
|
||||||
|
},
|
||||||
|
resRouteSuffix: this.routerKey,
|
||||||
|
target: {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private sendSearchRankingCmd(keywords: string, shopName: string, type: string, cacheTime: number) {
|
||||||
|
this.amqpAdmin.getTemplate().convertAndSend('client.topic.exchange', 'cmd_req', {
|
||||||
|
cmd: 'scout._1688Ranking',
|
||||||
|
data: {
|
||||||
|
keywords: keywords,
|
||||||
|
selector: {
|
||||||
|
shopName
|
||||||
|
},
|
||||||
|
cacheKey: this.getResultCacheKey(keywords, type, cacheTime),
|
||||||
|
cacheTime
|
||||||
|
},
|
||||||
|
resRouteSuffix: this.routerKey,
|
||||||
|
target: {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得关键词+类型的上次查询时间
|
||||||
|
* @param keywords 关键词
|
||||||
|
* @param type 类型
|
||||||
|
*/
|
||||||
|
private getCacheKey(keywords: string, type: string) {
|
||||||
|
return `SearchRanking:${keywords}:${type}`
|
||||||
|
}
|
||||||
|
private getResultCacheKey(keywords: string, type: string, date: number) {
|
||||||
|
return `SearchRanking:${keywords}:${type}:${date}`
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user