From 661c6b37118c9b9cfe3ea7e7ada36efa985562ee Mon Sep 17 00:00:00 2001 From: fofolee Date: Sun, 17 Apr 2022 18:14:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BF=AB=E6=8D=B7=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E6=9C=8D=E5=8A=A1=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/preload.js | 367 ++++++++++-------- src/App.vue | 10 + src/assets/feature/api.png | Bin 0 -> 3586 bytes src/assets/feature/crontab.png | Bin 0 -> 3759 bytes src/boot/global.js | 2 +- src/components/CommandEditor.vue | 1 + src/components/ConfigurationMenu.vue | 272 ++++++++----- src/components/MonacoEditor.vue | 5 +- src/components/quickFeatures/ApiServer.vue | 127 ++++++ src/components/quickFeatures/CrontabCmd.vue | 55 +++ src/components/quickFeatures/FavFile.vue | 40 ++ src/components/quickFeatures/FavUrl.vue | 76 ++++ .../quickFeatures/PluginNickName.vue | 144 +++++++ src/js/options/defaultProfile.js | 10 + src/js/options/quickFeatures.js | 16 +- src/pages/quickFeaturesPage.vue | 251 +----------- 16 files changed, 878 insertions(+), 498 deletions(-) create mode 100644 src/assets/feature/api.png create mode 100644 src/assets/feature/crontab.png create mode 100644 src/components/quickFeatures/ApiServer.vue create mode 100644 src/components/quickFeatures/CrontabCmd.vue create mode 100644 src/components/quickFeatures/FavFile.vue create mode 100644 src/components/quickFeatures/FavUrl.vue create mode 100644 src/components/quickFeatures/PluginNickName.vue diff --git a/plugin/preload.js b/plugin/preload.js index 90c0fbf..d219977 100644 --- a/plugin/preload.js +++ b/plugin/preload.js @@ -9,6 +9,8 @@ const { } = require('./lib/vm2') const path = require("path") const axios = require('axios'); +const http = require('http'); +const url = require('url') window._ = require("lodash") window.yuQueClient = axios.create({ @@ -266,154 +268,6 @@ let getSleepCodeByShell = ms => { return cmd } -// 屏蔽危险函数 -window.getuToolsLite = () => { - var utoolsLite = Object.assign({}, utools) - if (utools.isDev()) return utoolsLite - // 数据库相关接口 - delete utoolsLite.db - delete utoolsLite.dbStorage - delete utoolsLite.removeFeature - delete utoolsLite.setFeature - delete utoolsLite.onDbPull - // 支付相关接口 - delete utoolsLite.fetchUserServerTemporaryToken - delete utoolsLite.getUserServerTemporaryToken - delete utoolsLite.openPayment - delete utoolsLite.fetchUserPayments - return utoolsLite -} - -let getSandboxFuns = () => { - var sandbox = { - utools: getuToolsLite(), - quickcommand: quickcommand, - electron: electron, - axios: axios, - Audio: Audio, - fetch: fetch - } - shortCodes.forEach(f => { - sandbox[f.name] = f - }) - return sandbox -} - -let createNodeVM = () => { - var sandbox = getSandboxFuns() - const vm = new NodeVM({ - require: { - external: true, - builtin: ["*"], - }, - console: 'redirect', - env: process.env, - sandbox: sandbox, - }); - return vm -} - -let stringifyAll = item => { - var cache = []; - var string = JSON.stringify(item, (key, value) => { - if (typeof value === 'object' && value !== null) { - if (cache.indexOf(value) !== -1) return - cache.push(value); - } - return value; - }, '\t') - if (string != "{}") return string - else return item.toString() -} - -let parseItem = item => { - if (typeof item == "object") { - if (Buffer.isBuffer(item)) { - var bufferString = `[Buffer ${item.slice(0, 50).toString('hex').match(/\w{1,2}/g).join(" ")}` - if (item.length > 50) bufferString += `... ${(item.length / 1000).toFixed(2)}kb` - return bufferString + ']' - } else if (item instanceof ArrayBuffer) { - return `ArrayBuffer(${item.byteLength})` - } else if (item instanceof Blob) { - return `Blob {size: ${item.size}, type: "${item.type}"}` - } else { - try { - return stringifyAll(item) - } catch (error) {} - } - } else if (typeof item == "undefined") { - return "undefined" - } - return item.toString() -} - -window.convertFilePathToUtoolsPayload = files => files.map(file => { - let isFile = fs.statSync(file).isFile() - return { - isFile: isFile, - isDirectory: !isFile, - name: path.basename(file), - path: file - } -}) - -let parseStdout = stdout => stdout.map(x => parseItem(x)).join("\n") - -window.VmEval = (cmd, sandbox = {}) => new VM({ - sandbox: sandbox -}).run(cmd) - -// The vm module of Node.js is deprecated in the renderer process and will be removed -window.runCodeInVm = (cmd, cb) => { - const vm = createNodeVM() - //重定向 console - vm.on('console.log', (...stdout) => { - console.log(stdout); - cb(parseStdout(stdout), null) - }); - - vm.on('console.error', stderr => { - cb(null, stderr.toString()) - }); - - let liteErr = e => { - if (!e) return - return e.stack.replace(/([ ] +at.+)|(.+\.js:\d+)/g, '').trim() - } - - // 错误处理 - try { - vm.run(cmd, path.join(__dirname, 'preload.js')); - } catch (e) { - console.log('Error: ', e) - cb(null, liteErr(e)) - } - - let cbUnhandledError = e => { - removeAllListener() - console.log('UnhandledError: ', e) - cb(null, liteErr(e.error)) - } - - let cbUnhandledRejection = e => { - removeAllListener() - console.log('UnhandledRejection: ', e) - cb(null, liteErr(e.reason)) - } - - let removeAllListener = () => { - window.removeEventListener('error', cbUnhandledError) - window.removeEventListener('unhandledrejection', cbUnhandledRejection) - delete window.isWatchingError - } - - if (!window.isWatchingError) { - window.addEventListener('error', cbUnhandledError) - window.addEventListener('unhandledrejection', cbUnhandledRejection) - window.isWatchingError = true - } -} - window.htmlEncode = (value) => { return String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/ { return pwdFix.replace(/\\/g, '\\\\') } -window.getMatchedFilesFix = payload => { - let MatchedFiles = payload - let Matched = cmd.match(/\{\{MatchedFiles(\[\d+\]){0,1}(\.\w{1,11}){0,1}\}\}/g) - Matched && Matched.forEach(m => { - repl = eval(m.slice(2, -2)) - typeof repl == 'object' ? (repl = JSON.stringify(repl)) : (repl = repl.replace('\\', '\\\\')) - cmd = cmd.replace(m, repl.replace('$', '$$$')) - }) -} - window.saveFile = (content, file) => { if (file instanceof Object) file = utools.showSaveDialog(file) if (!file) return false @@ -559,6 +403,156 @@ window.getSelectFile = hwnd => { window.clipboardReadText = () => electron.clipboard.readText() +window.convertFilePathToUtoolsPayload = files => files.map(file => { + let isFile = fs.statSync(file).isFile() + return { + isFile: isFile, + isDirectory: !isFile, + name: path.basename(file), + path: file + } +}) + +let stringifyAll = item => { + var cache = []; + var string = JSON.stringify(item, (key, value) => { + if (typeof value === 'object' && value !== null) { + if (cache.indexOf(value) !== -1) return + cache.push(value); + } + return value; + }, '\t') + if (string != "{}") return string + else return item.toString() +} + +let parseItem = item => { + if (typeof item == "object") { + if (Buffer.isBuffer(item)) { + var bufferString = `[Buffer ${item.slice(0, 50).toString('hex').match(/\w{1,2}/g).join(" ")}` + if (item.length > 50) bufferString += `... ${(item.length / 1000).toFixed(2)}kb` + return bufferString + ']' + } else if (item instanceof ArrayBuffer) { + return `ArrayBuffer(${item.byteLength})` + } else if (item instanceof Blob) { + return `Blob {size: ${item.size}, type: "${item.type}"}` + } else { + try { + return stringifyAll(item) + } catch (error) {} + } + } else if (typeof item == "undefined") { + return "undefined" + } + return item.toString() +} + +let parseStdout = stdout => stdout.map(x => parseItem(x)).join("\n") + +// 屏蔽危险函数 +window.getuToolsLite = () => { + var utoolsLite = Object.assign({}, utools) + if (utools.isDev()) return utoolsLite + // 数据库相关接口 + delete utoolsLite.db + delete utoolsLite.dbStorage + delete utoolsLite.removeFeature + delete utoolsLite.setFeature + delete utoolsLite.onDbPull + // 支付相关接口 + delete utoolsLite.fetchUserServerTemporaryToken + delete utoolsLite.getUserServerTemporaryToken + delete utoolsLite.openPayment + delete utoolsLite.fetchUserPayments + return utoolsLite +} + +let getSandboxFuns = () => { + var sandbox = { + utools: getuToolsLite(), + quickcommand: quickcommand, + electron: electron, + axios: axios, + Audio: Audio, + fetch: fetch + } + shortCodes.forEach(f => { + sandbox[f.name] = f + }) + return sandbox +} + +let createNodeVM = (userVars) => { + var sandbox = getSandboxFuns() + Object.assign(userVars, sandbox) + const vm = new NodeVM({ + require: { + external: true, + builtin: ["*"], + }, + console: 'redirect', + env: process.env, + sandbox: userVars, + }); + return vm +} + +window.VmEval = (cmd, sandbox = {}) => new VM({ + sandbox: sandbox +}).run(cmd) + +let isWatchingError = false +// The vm module of Node.js is deprecated in the renderer process and will be removed +window.runCodeInVm = (cmd, callback, userVars = {}) => { + const vm = createNodeVM(userVars) + //重定向 console + vm.on('console.log', (...stdout) => { + console.log(stdout); + callback(parseStdout(stdout), null) + }); + + vm.on('console.error', stderr => { + callback(null, stderr.toString()) + }); + + let liteErr = e => { + if (!e) return + return e.stack.replace(/([ ] +at.+)|(.+\.js:\d+)/g, '').trim() + } + + // 错误处理 + try { + vm.run(cmd, path.join(__dirname, 'preload.js')); + } catch (e) { + console.log('Error: ', e) + callback(null, liteErr(e)) + } + + let cbUnhandledError = e => { + removeAllListener() + console.log('UnhandledError: ', e) + callback(null, liteErr(e.error)) + } + + let cbUnhandledRejection = e => { + removeAllListener() + console.log('UnhandledRejection: ', e) + callback(null, liteErr(e.reason)) + } + + let removeAllListener = () => { + window.removeEventListener('error', cbUnhandledError) + window.removeEventListener('unhandledrejection', cbUnhandledRejection) + isWatchingError = false + } + + if (!isWatchingError) { + window.addEventListener('error', cbUnhandledError) + window.addEventListener('unhandledrejection', cbUnhandledRejection) + isWatchingError = true + } +} + window.runCodeFile = (cmd, option, terminal, callback) => { var bin = option.bin, argv = option.argv, @@ -609,4 +603,61 @@ window.runCodeFile = (cmd, option, terminal, callback) => { // let stderr = err_chunks.join(""); // callback(stdout, stderr) // }) +} + +let httpServer +window.quickcommandHttpServer = () => { + let run = (cmd = '', port = 33442) => { + let httpResponse = (res, code, result) => { + // 因为无法判断 vm2 是否执行完毕,故只收受一次 console.log,接收后就关闭连接 + if (res.finished) return + res.writeHead(code, { + 'Content-Type': 'text/html' + }); + if (result) res.write(result); + res.end(); + } + let runUserCode = (res, cmd, userVars) => { + // 不需要返回输出的提前关闭连接 + if (!cmd.includes('console.log')) httpResponse(res, 200) + window.runCodeInVm(cmd, (stdout, stderr) => { + // 错误返回 500 + if (stderr) return httpResponse(res, 500, stderr) + return httpResponse(res, 200, stdout) + }, userVars) + } + httpServer = http.createServer() + httpServer.on('request', (req, res) => { + if (req.method === 'GET') { + let parsedParams = _.cloneDeep(url.parse(req.url, true).query) + runUserCode(res, cmd, parsedParams) + } else if (req.method === 'POST') { + let data = [] + req.on('data', (chunk) => { + data.push(chunk) + }) + req.on('end', () => { + let parsedParams + let params = data.join("").toString() + // 先尝试作为 json 解析 + try { + parsedParams = JSON.parse(params) + } catch (error) { + parsedParams = _.cloneDeep(url.parse('?' + params, true).query) + } + runUserCode(res, cmd, parsedParams) + }) + } else { + httpResponse(res, 405) + } + }) + httpServer.listen(port, 'localhost'); + } + let stop = () => { + httpServer.close() + } + return { + run, + stop + } } \ No newline at end of file diff --git a/src/App.vue b/src/App.vue index 9d5d317..42ad3c4 100644 --- a/src/App.vue +++ b/src/App.vue @@ -33,6 +33,16 @@ export default defineComponent({ }); return; } + // 如果配置了后台服务则开启监听 + if (this.$profile.quickFeatures.apiServer.serverStatus) { + window + .quickcommandHttpServer() + .run( + this.$profile.quickFeatures.apiServer.cmd, + this.$profile.quickFeatures.apiServer.port + ); + console.log("Server Start..."); + } // 默认主题色 this.setCssVar("primary", this.$profile.primaryColor); // 进入插件 diff --git a/src/assets/feature/api.png b/src/assets/feature/api.png new file mode 100644 index 0000000000000000000000000000000000000000..c4233973fa625c8f643e2262cc4fade9959635e5 GIT binary patch literal 3586 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 + + 实用功能 + + + + + + + + + 启用后,选中文件可以通过超级面板快速将文件收藏到「{{ + quickFeatures.favFile.tag + }}」标签 + + + + + + + + + + 启用后,在浏览器界面可以通过超级面板快速将网址收藏到「{{ + quickFeatures.favUrl.tag + }}」标签 + + + + + + + + + + 启用后,在主输入框输入「插件别名」可以快速设置插件别名
+ 并将所有设置的别名保存至「{{ + quickFeatures.pluNickName.tag + }}」标签 +
+
+
+ + + + + + + 启用后,在主输入框输入「计划任务」可以配置计划任务,定制执行指定或新建的快捷命令
+ 如果是直接新建,则新建的任务会保存在「{{ + quickFeatures.crontab.tag + }}」标签
+ 注意此功能并没有使用系统自带的计划任务,需要配置插件跟随 + utools 启动和保留后台
+ 本功能比系统自带的更为强大,因为你可以在计划任务中任意使用 + utools 或 quickcommand 的 api +
+
+
+ + + + + + + 启用后,在主输入框输入「快捷命令服务」可以进入配置一个后台服务
+ 通过本地监听{{ + quickFeatures.apiServer.port + }}端口的形式,接收用户传送过来的参数,然后根据参数执行不同的操作 +
+ 本功能的意义在于,将 utools + 的接口暴露出来,可以通过命令行等外部途径
+ 直接启用 ubrowser 或者直接redirect 到相应的插件
+ 需要配置插件跟随 utools 启动和保留后台 +
+
+
+
+
+ @@ -77,108 +247,6 @@ - - - - - - 实用功能 - - - - - - - - - 启用后,选中文件可以通过超级面板快速将文件收藏到「{{ - quickFeatures.favFile.tag - }}」标签 - - - - - - - - - - 启用后,在浏览器界面可以通过超级面板快速将网址收藏到「{{ - quickFeatures.favUrl.tag - }}」标签 - - - - - - - - - - 启用后,在主输入框输入「插件别名」可以快速设置插件别名
- 并将所有设置的别名保存至「{{ - quickFeatures.pluNickName.tag - }}」标签 -
-
-
-
-
-
diff --git a/src/components/MonacoEditor.vue b/src/components/MonacoEditor.vue index acd951f..0faa9bb 100644 --- a/src/components/MonacoEditor.vue +++ b/src/components/MonacoEditor.vue @@ -1,7 +1,7 @@ + + diff --git a/src/components/quickFeatures/CrontabCmd.vue b/src/components/quickFeatures/CrontabCmd.vue new file mode 100644 index 0000000..f461aa2 --- /dev/null +++ b/src/components/quickFeatures/CrontabCmd.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/src/components/quickFeatures/FavFile.vue b/src/components/quickFeatures/FavFile.vue new file mode 100644 index 0000000..d5d6178 --- /dev/null +++ b/src/components/quickFeatures/FavFile.vue @@ -0,0 +1,40 @@ + diff --git a/src/components/quickFeatures/FavUrl.vue b/src/components/quickFeatures/FavUrl.vue new file mode 100644 index 0000000..0b8f513 --- /dev/null +++ b/src/components/quickFeatures/FavUrl.vue @@ -0,0 +1,76 @@ + diff --git a/src/components/quickFeatures/PluginNickName.vue b/src/components/quickFeatures/PluginNickName.vue new file mode 100644 index 0000000..c223aaf --- /dev/null +++ b/src/components/quickFeatures/PluginNickName.vue @@ -0,0 +1,144 @@ + + + diff --git a/src/js/options/defaultProfile.js b/src/js/options/defaultProfile.js index b1147c3..656e84d 100644 --- a/src/js/options/defaultProfile.js +++ b/src/js/options/defaultProfile.js @@ -17,5 +17,15 @@ export default { enable: false, tag: "别名" }, + crontab: { + enable: false, + tag: "任务" + }, + apiServer: { + enable: false, + port: 33442, + cmd: "", + serverStatus: false + } } } \ No newline at end of file diff --git a/src/js/options/quickFeatures.js b/src/js/options/quickFeatures.js index aa3142a..375ce9e 100644 --- a/src/js/options/quickFeatures.js +++ b/src/js/options/quickFeatures.js @@ -42,7 +42,21 @@ const quickFeatures = { cmds: ["插件别名"], icon: require("../../assets/feature/plugin.png"), platform: ["win32", "darwin", "linux"], + }, + crontab: { + code: "feature_crontab", + explain: "为快捷命令添加计划任务", + cmds: ["计划任务", "crontab"], + icon: require("../../assets/feature/crontab.png"), + platform: ["win32", "darwin", "linux"], + }, + apiServer: { + code: "feature_apiServer", + explain: "配置快捷命令后台服务", + cmds: ["快捷命令服务配置", "quickcommandServer"], + icon: require("../../assets/feature/api.png"), + platform: ["win32", "darwin", "linux"], } } -export default quickFeatures +export default quickFeatures \ No newline at end of file diff --git a/src/pages/quickFeaturesPage.vue b/src/pages/quickFeaturesPage.vue index 646db64..0c29b01 100644 --- a/src/pages/quickFeaturesPage.vue +++ b/src/pages/quickFeaturesPage.vue @@ -1,244 +1,29 @@