diff --git a/packages/plugins/src/MiaoConsole.ts b/packages/plugins/src/MiaoConsole.ts
index 34acc38a..744f0a2b 100644
--- a/packages/plugins/src/MiaoConsole.ts
+++ b/packages/plugins/src/MiaoConsole.ts
@@ -1,3 +1,4 @@
+///
///
///
///
@@ -56,7 +57,7 @@ export class MiaoConsole extends interfaces.Plugin {
this.token = Java.type('java.util.UUID').randomUUID().toString()
this.logger.console(`§6已生成随机Token: §3${this.token} §c重启后或重新生成后失效!`)
}
- global.eventCenter.on('log', (msg) => {
+ process.on('message', (msg) => {
this.logCache.push(msg)
if (this.logCache.length > 30) {
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, {
append: (logEvent) => {
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) {
let AbstractHandler = Java.type('java.util.logging.Handler')
let ProxyHandler = Java.extend(AbstractHandler, {
- publish: (record) => global.eventCenter.emit('log', record.getMessage()),
+ publish: (record) => process.emit('message', record.getMessage()),
flush: () => { },
close: () => { }
})
@@ -162,7 +163,7 @@ export class MiaoConsole extends interfaces.Plugin {
if (this.rootLogger) {
let AppenderBase = Java.type('ch.qos.logback.core.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.start()
@@ -175,7 +176,7 @@ export class MiaoConsole extends interfaces.Plugin {
disable() {
if (this.socketIOServer) {
this.socketIOServer.close()
- global.eventCenter.removeAllListeners('log')
+ process.removeAllListeners('message')
}
if (this.container.isBound(io.Instance)) {
this.container.unbind(io.Instance)
@@ -220,7 +221,7 @@ export class MiaoConsole extends interfaces.Plugin {
startSocketIOServer() {
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) => {
if (!this.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)
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) => {
try {
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) => {
- let dir = fs.file(file);
+ let dir = fs.file(file)
if (!dir.isDirectory()) {
return fn(undefined, `${file} 不是一个目录!`)
}
@@ -309,10 +313,9 @@ export class MiaoConsole extends interfaces.Plugin {
if (this.serverType == "spring") {
var dbm = container.get(api.database.DataBaseManager)
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)) + ''
}
}
diff --git a/packages/plugins/src/MiaoProtocol.ts b/packages/plugins/src/MiaoProtocol.ts
new file mode 100644
index 00000000..ed22b400
--- /dev/null
+++ b/packages/plugins/src/MiaoProtocol.ts
@@ -0,0 +1,32 @@
+///
+
+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()
+ }
+
+}
diff --git a/packages/plugins/src/MiaoScriptPackageManager.ts b/packages/plugins/src/MiaoScriptPackageManager.ts
index 124e779a..861384ee 100644
--- a/packages/plugins/src/MiaoScriptPackageManager.ts
+++ b/packages/plugins/src/MiaoScriptPackageManager.ts
@@ -1,10 +1,11 @@
import { plugin as pluginApi, task, server } from '@ccms/api'
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 * as fs from '@ccms/common/dist/fs'
+import * as reflect from '@ccms/common/dist/reflect'
import http from '@ccms/common/dist/http'
let help = [
@@ -19,7 +20,7 @@ let help = [
'§6/mpm §arun §e §6- §3运行JS代码',
'§6/mpm §adeploy §e<插件名称> §6- §3发布插件',
'§6/mpm §crestart §6- §4重启MiaoScript脚本引擎'
-];
+]
let langMap = {
'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 })
export class MiaoScriptPackageManager extends interfaces.Plugin {
@inject(pluginApi.PluginManager)
- private pluginManager: pluginApi.PluginManager;
+ private pluginManager: pluginApi.PluginManager
@inject(task.TaskManager)
- private taskManager: task.TaskManager;
+ private taskManager: task.TaskManager
@inject(server.ServerType)
- private serverType: string;
+ private serverType: string
@inject(server.Server)
private server: server.Server
@inject(pluginApi.PluginFolder)
- private pluginFolder: string;
+ private pluginFolder: string
private packageCache: any[] = [];
private packageNameCache: string[] = [];
- private translate: Translate;
+ private translate: Translate
load() {
this.translate = new Translate({
@@ -78,7 +79,7 @@ export class MiaoScriptPackageManager extends interfaces.Plugin {
@cmd()
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) {
@@ -90,64 +91,64 @@ export class MiaoScriptPackageManager extends interfaces.Plugin {
if (!this[cmdKey]) {
this.i18n(sender, 'main.command.not.exists', { command: args[0] })
this.i18n(sender, 'main.command.help.tip', { command })
- return;
+ return
}
args.shift()
- this[cmdKey](sender, ...args);
+ this[cmdKey](sender, ...args)
}
cmdhelp(sender: any) {
- this.logger.sender(sender, help);
+ this.logger.sender(sender, help)
}
cmdload(sender: any, name: string) {
- let pluginFile = fs.concat(__dirname + '', name);
+ let pluginFile = fs.concat(__dirname + '', name)
if (!fs.exists(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') {
if (type == "i" || type == "install") {
this.i18n(sender, 'list.install.header')
this.pluginManager.getPlugins().forEach((plugin) => {
- this.i18n(sender, 'list.install.body', plugin.description);
+ this.i18n(sender, 'list.install.body', plugin.description)
})
} else {
this.i18n(sender, 'list.header')
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) {
if (!name) { return this.i18n(sender, 'plugin.name.empty') }
- this.download(sender, name);
+ this.download(sender, name)
}
cmdupdate(sender: any, name: string) {
if (name) {
- this.update(sender, name);
+ this.update(sender, name)
} else {
this.updateRepo(sender)
}
}
cmdupgrade(sender: any, name: string) {
- if (!name) { return this.i18n(sender, 'upgrade.confirm'); }
+ if (!name) { return this.i18n(sender, 'upgrade.confirm') }
if (name == "comfirm") {
let enginePath = fs.path(fs.file(fs.concat(root, 'node_modules', '@ccms')))
if (enginePath.startsWith(root)) {
- base.delete(enginePath);
- this.cmdrestart(sender);
+ base.delete(enginePath)
+ this.cmdrestart(sender)
}
}
if (this.checkPlugin(sender, name)) {
- this.update(sender, name);
- this.pluginManager.reload(name);
+ this.update(sender, name)
+ this.pluginManager.reload(name)
}
}
@@ -161,7 +162,7 @@ export class MiaoScriptPackageManager extends interfaces.Plugin {
cmdreload(sender: any, name: string) {
name = name || this.description.name
if (this.checkPlugin(sender, name)) {
- this.pluginManager.reload(name);
+ this.pluginManager.reload(name)
this.i18n(sender, 'plugin.reload.finish', { name })
}
}
@@ -184,33 +185,58 @@ export class MiaoScriptPackageManager extends interfaces.Plugin {
return
}
try {
- this.logger.sender(sender, '§6Reloading §3MiaoScript Engine...');
- ScriptEngineContextHolder.disableEngine();
- Packages.java.lang.System.gc();
- ScriptEngineContextHolder.enableEngine();
- this.logger.sender(sender, '§3MiaoScript Engine §6Reload §aSuccessful...');
+ this.logger.sender(sender, '§6Reloading §3MiaoScript Engine...')
+ ScriptEngineContextHolder.disableEngine()
+ Packages.java.lang.System.gc()
+ ScriptEngineContextHolder.enableEngine()
+ this.logger.sender(sender, '§3MiaoScript Engine §6Reload §aSuccessful...')
} catch (ex) {
- this.logger.sender(sender, "§3MiaoScript Engine §6Reload §cError! ERR: " + ex);
- this.logger.sender(sender, this.logger.stack(ex));
+ this.logger.sender(sender, "§3MiaoScript Engine §6Reload §cError! ERR: " + ex)
+ this.logger.sender(sender, this.logger.stack(ex))
}
}
cmdrun(sender: any, ...args: any[]) {
try {
- let script = args.join(' ');
+ let script = args.join(' ')
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 + '' })
} 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) {
if (!process.env.AccessToken) { return this.i18n(sender, 'deploy.token.not.exists') }
this.taskManager.create(() => {
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, {
name,
author: plugin.description.author,
@@ -224,7 +250,7 @@ export class MiaoScriptPackageManager extends interfaces.Plugin {
update(sender: any, name: string) {
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":
return ["install", "cloud"]
case "install":
- return this.packageNameCache;
+ return this.packageNameCache
case "update":
case "upgrade":
case "load":
case "unload":
case "reload":
case "deploy":
- return [...this.pluginManager.getPlugins().keys()];
+ return [...this.pluginManager.getPlugins().keys()]
}
}
}
updateRepo(sender: any) {
this.taskManager.create(() => {
- let result = http.get('http://ms.yumc.pw/api/plugin/list');
- for (const pl of result.data) { this.packageCache[pl.name] = pl; }
- this.packageNameCache = Object.keys(this.packageCache);
+ let result = http.get('http://ms.yumc.pw/api/plugin/list')
+ for (const pl of result.data) { this.packageCache[pl.name] = pl }
+ this.packageNameCache = Object.keys(this.packageCache)
this.i18n(sender, 'cloud.update.finish', { length: this.packageNameCache.length })
- }).async().submit();
+ }).async().submit()
}
download(sender: any, name: string, update: boolean = false) {
diff --git a/packages/plugins/src/MiaoSpring.ts b/packages/plugins/src/MiaoSpring.ts
index 61944fb3..7ecf38a3 100644
--- a/packages/plugins/src/MiaoSpring.ts
+++ b/packages/plugins/src/MiaoSpring.ts
@@ -2,58 +2,30 @@
///
///
-import { constants, database, plugin } from "@ccms/api"
-import { inject, ContainerInstance, Container, JSClass } from "@ccms/container"
+import { constants, database, plugin, web } from "@ccms/api"
+import { inject, ContainerInstance, Container } from "@ccms/container"
import { JSPlugin, interfaces, cmd } from "@ccms/plugin"
import { DataBase, DataBaseManager } from '@ccms/database'
+import { Server, Context, RequestHandler } from '@ccms/web'
+
import * as fs from '@ccms/common/dist/fs'
import * as reflect from '@ccms/common/dist/reflect'
-import * as querystring from 'querystring'
-const WebProxyBeanName = 'webServerProxy'
-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 })
+@JSPlugin({ name: 'MiaoSpring', prefix: 'MSpring', version: '1.0.1', author: 'MiaoWoo', servers: [constants.ServerType.Spring], source: __filename })
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)
private container: Container
- @inject(plugin.PluginInstance)
- private context: any
@inject(plugin.PluginManager)
private pluginManager: plugin.PluginManager
@inject(database.DataBaseManager)
private databaseManager: DataBaseManager
+ @inject(web.Server)
+ private webServer: Server
+
+ private ResponseEntity = org.springframework.http.ResponseEntity
- private beanFactory: any
private mainDatabase: DataBase
- private interceptors: InterceptorAdapter[] = []
- private requestMapping: { [key: string]: RequestHandler } = {}
+ private mappings: Set
@cmd()
mspring(sender: any) {
@@ -62,144 +34,24 @@ export class MiaoSpring extends interfaces.Plugin {
}
load() {
- this.beanFactory = this.context.getAutowireCapableBeanFactory()
this.mainDatabase = this.databaseManager.getMainDatabase()
+ this.mappings = new Set()
}
enable() {
- this.registryWebBean()
this.registryDefault()
this.registryPages()
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) {
- this.requestMapping[path] = handler
+ this.mappings.add(path)
+ this.webServer.registryMapping(path, handler)
}
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']
- this.interceptors.push({
+ this.webServer.registryInterceptor({
name: 'RedirectHandle',
preHandle: (ctx: Context) => {
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',
preHandle: (ctx: Context) => {
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 {
return { status: 200, data: this.runCode(ctx.body + ''), msg: '代码执行成功!' }
} catch (error) {
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: '插件列表获取成功!' }
})
- this.registryMapping('/api/plugin/update', (ctx: Context) => {
+ this.webServer.registryMapping('/api/plugin/update', (ctx: Context) => {
if (!ctx.params.name) { return { status: 400, msg: '插件名称不得为空!' } }
})
}
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') } }
})
- this.registryMapping('/api/page/get', (ctx: Context) => {
+ this.webServer.registryMapping('/api/page/get', (ctx: Context) => {
let name = decodeURIComponent(`${ctx.params.name}`)
let varable = undefined
if (!name) { return { status: 400, msg: '名称不能为空!' } }
@@ -265,20 +117,20 @@ Handle Time : ${preHandleTime + execTime + postHandleTime}ms
}
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
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)
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 不能为空!' } }
const body = ctx.body
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)
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: '页面 名称 不能为空!' } }
this.mainDatabase.update("UPDATE `pages` SET `name` = CONCAT(name, '_deleted'), deleted = 1 WHERE name = ?", ctx.params.name)
return { status: 0, msg: `${ctx.params.name} 删除成功!` }
@@ -288,17 +140,17 @@ Handle Time : ${preHandleTime + execTime + postHandleTime}ms
private configTable = "config"
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) }
})
- this.registryMapping('/api/config/get', (ctx: Context) => {
+ this.webServer.registryMapping('/api/config/get', (ctx: Context) => {
let name = ctx.params.name
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)
if (!result.length) { return { status: 404, msg: `配置 ${name} 不存在!` } }
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
if (!body.name) { return { status: 400, msg: '名称不能为空!' } }
this.mainDatabase.update(
@@ -307,7 +159,7 @@ Handle Time : ${preHandleTime + execTime + postHandleTime}ms
)
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 不能为空!' } }
let body = ctx.body
this.mainDatabase.update(
@@ -327,7 +179,6 @@ Handle Time : ${preHandleTime + execTime + postHandleTime}ms
'pluginManager'
]
let params = [
- this.beanFactory,
this.mainDatabase,
reflect,
this.container,
@@ -341,7 +192,6 @@ return eval(${JSON.stringify(code)});`)
}
disable() {
- Object.keys(this.requestMapping).forEach((r) => delete this.requestMapping[r])
- this.beanFactory.destroySingleton(WebProxyBeanName)
+ Object.keys(this.mappings).forEach((r) => this.webServer.unregistryMapping(r))
}
}
diff --git a/packages/plugins/src/SearchRanking.ts b/packages/plugins/src/SearchRanking.ts
new file mode 100644
index 00000000..9a68e08a
--- /dev/null
+++ b/packages/plugins/src/SearchRanking.ts
@@ -0,0 +1,181 @@
+///
+///
+
+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(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}`
+ }
+}