From b471c9f379a5153c8fb7cc9eab76606491c25752 Mon Sep 17 00:00:00 2001 From: qingkou Date: Wed, 31 Jul 2019 12:26:05 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0device=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Readme | 1 - Readme.md | 18 +++++++++++++ bin/hotnode.js | 0 config.js | 13 ++++++++++ device.js | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++ index.js | 31 +++++++++++++++++++++++ package.json | 20 +++++++++++++++ 7 files changed, 150 insertions(+), 1 deletion(-) delete mode 100644 Readme create mode 100644 Readme.md create mode 100644 bin/hotnode.js create mode 100644 config.js create mode 100644 device.js create mode 100644 index.js create mode 100644 package.json diff --git a/Readme b/Readme deleted file mode 100644 index a57a248..0000000 --- a/Readme +++ /dev/null @@ -1 +0,0 @@ -作业 diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..13ab36e --- /dev/null +++ b/Readme.md @@ -0,0 +1,18 @@ +# tast + +写一个 web 服务,提供以下服务: +GET 接口 `/device?pw=cpu&sort=desc`,返回: + +```js +{ + cpu:{}, // 服务器cpu状态 + mem:{}, // 服务器内存状态 + proc:[] // 全量进程列表(默认按cpu和降序排列) +} +``` + +写一个守护进程: +同目录下写一个 bin/hotnode 最终通过`hotnode app.js`启动服务。 +并在 app.js 文件变更后自动重启 app.js 进程 + +## \ No newline at end of file diff --git a/bin/hotnode.js b/bin/hotnode.js new file mode 100644 index 0000000..e69de29 diff --git a/config.js b/config.js new file mode 100644 index 0000000..c8bdfb3 --- /dev/null +++ b/config.js @@ -0,0 +1,13 @@ +module.exports = { + // 服务器配置 + server: { + host: "127.0.0.1", + port: 3000 + }, + // 默认参数 + query: { + sort: "asce", // Asce升序,desc降序 + keyword: "cpu", // cpu/mem/pid/start + len: 10 // 显示条数 + } +}; diff --git a/device.js b/device.js new file mode 100644 index 0000000..e5bd49e --- /dev/null +++ b/device.js @@ -0,0 +1,68 @@ +const os = require("os"); +const util = require("util"); +const querystring = require("querystring"); +const exec = util.promisify(require("child_process").exec); + +/* 获取系统信息 */ +const getData = async function(opt) { + const cpu = await getInfo("cpu"), + mem = await getInfo("mem"), + proc = await getInfo("proc", opt); + + return { + cpu, + mem, + proc + }; +}; + +const getInfo = async function(type, opt) { + const command = getCommand(type, opt); + const { stdout, stderr } = await exec(command); + if (stderr) throw stderr; + return stdout.split("\n").slice(1, -1); +}; + +const getCommand = function(type, opt) { + // 非linux系统时,命令暂时瞎写 + const commands = + os.platform() == "linux" + ? { + cpu: "cat /proc/cpuinfo", + mem: "cat /proc/meminfo" + } + : { + cpu: "ls -l", + mem: "ls -al", + proc: "ps aux | head -n 5" + }; + + if (os.platform() == "linux" && type === "proc") + commands.proc = `ps aux --sort=${opt.sort === "asce" ? "" : "-"}%${ + opt.keyword + } | head -n ${opt.len - 0 + 1}`; + + return commands[type]; +}; + +const requestParse = function(req) { + const [host, port] = req.headers.host.split(":"), + urlObj = req.url.indexOf("?") === -1 ? [req.url, null] : req.url.split("?"), + urlPath = /.+\/$/.test(urlObj[0]) + ? urlObj[0].substr(0, urlObj[0].length - 1) + : urlObj[0], + urlQuery = urlObj[1] === null ? {} : querystring.parse(urlObj[1]); + + return { + method: req.headers.method, + host: host[0], + port: port[1] || 80, + path: urlPath, + query: urlQuery + }; +}; + +module.exports = { + getData, + requestParse +}; diff --git a/index.js b/index.js new file mode 100644 index 0000000..2aea25c --- /dev/null +++ b/index.js @@ -0,0 +1,31 @@ +const os = require("os"); +const http = require("http"); +const config = require("./config.js"); +const device = require("./device.js"); + +http + .createServer(async (req, res) => { + const parsedReq = device.requestParse(req), + query = Object.assign({}, config.query, parsedReq.query); + let data = {}; + + if (parsedReq.path === "/device") { + res.statusCode = 200; + res.setHeader("content-type", "application/json"); + data = await device.getData(query); + try { + data = JSON.stringify(data); + } catch (err) { + data = "{}"; + } + } else { + res.statusCode = 404; + res.setHeader("content-type", "text/html"); + res.end("

404

"); + } + res.end(data); + }) + .listen(config.server.port, config.server.host, () => { + const svr = config.server; + console.log(`server is running at ${svr.host} : ${svr.port}`); + }); diff --git a/package.json b/package.json new file mode 100644 index 0000000..f03c26d --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "homework-nodejs", + "version": "1.0.0", + "description": "写一个 web 服务,提供以下服务: GET 接口 `/device?pw=cpu&sort=desc`,返回:", + "main": "index.js", + "bin": { + "homework-nodejs": "hotnode.js" + }, + "scripts": { + "start": "node ./index.js", + "debug": "node --inspect-brk ./index.js" + }, + "repository": { + "type": "git", + "url": "git@github.com_qyingkou:qyingkou/homework-nodejs.git" + }, + "keywords": [], + "author": "qingkooo ", + "license": "MIT" +} From b5d0a74d3075d79ad79cc558f8e23887e76d2fd7 Mon Sep 17 00:00:00 2001 From: qingkou Date: Thu, 1 Aug 2019 22:30:23 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=88=E6=8A=A4?= =?UTF-8?q?=E8=BF=9B=E7=A8=8B=E5=90=AF=E5=8A=A8=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 27 +++++++++++++++++++++++++ .gitignore | 4 ++++ .vscode/launch.json | 16 +++++++++++++++ Readme.md | 24 +++++++++++++++------- bin/hotloader.js | 44 ++++++++++++++++++++++++++++++++++++++++ bin/hotnode | 23 +++++++++++++++++++++ bin/hotnode.js | 0 index.js | 49 ++++++++++++++++++++++----------------------- package.json | 33 ++++++++++++++---------------- 9 files changed, 170 insertions(+), 50 deletions(-) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 bin/hotloader.js create mode 100755 bin/hotnode delete mode 100644 bin/hotnode.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f7740fa --- /dev/null +++ b/.editorconfig @@ -0,0 +1,27 @@ +# EditorConfig is awesome: https://EditorConfig.org +# top-most EditorConfig file +root = true + +[*] +end_of_line = lf +indent_style = tab +tab_width = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.json] +insert_final_newline = ignore + +[**.{min,bundle}.js] +indent_style = ignore +insert_final_newline = ignore + +[Makefile] +indent_style = tab + +[*.bat] +indent_style = tab + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..302e6db --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +## folders +/node_modules + +## files diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8ed474c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Program", + "type": "node", + "request": "launch", + "program": "${workspaceFolder}/bin/hotnode", + "cwd": "${workspaceFolder}", + "args": ["-a", "./index.js"] + } + ] +} diff --git a/Readme.md b/Readme.md index 13ab36e..77f9b67 100644 --- a/Readme.md +++ b/Readme.md @@ -1,18 +1,28 @@ -# tast +# tasts -写一个 web 服务,提供以下服务: +1,写一个 web 服务,提供以下服务: GET 接口 `/device?pw=cpu&sort=desc`,返回: ```js { - cpu:{}, // 服务器cpu状态 - mem:{}, // 服务器内存状态 + cpu:[], // 服务器cpu状态 + mem:[], // 服务器内存状态 proc:[] // 全量进程列表(默认按cpu和降序排列) } ``` -写一个守护进程: +2,写一个守护进程启动器: 同目录下写一个 bin/hotnode 最终通过`hotnode app.js`启动服务。 -并在 app.js 文件变更后自动重启 app.js 进程 +在 app.js 文件变更后自动重启 app.js 进程 -## \ No newline at end of file +## 接口 + +## 守护进程启动器 + +### 参数设计: + +```cmd +// 参数说明 +-a, --application // 应用文件路径, "./index.js" +-w, --watch // 监听变化路径, "./"); +``` diff --git a/bin/hotloader.js b/bin/hotloader.js new file mode 100644 index 0000000..114ea8b --- /dev/null +++ b/bin/hotloader.js @@ -0,0 +1,44 @@ +const fs = require("fs"); +const path = require("path"); +const { spawn } = require("child_process"); + +class HotLoader { + static getInstance() { + if (!HotLoader.instance) { + HotLoader.instance = new HotLoader(); + } + return HotLoader.instance; + } + constructor() {} + + run(program) { + this.commander = program; + fs.watch(path.resolve(this.commander.application), (event, filename) => { + this.restartProcess(); + }); + this.startProgress(); + } + + startProgress() { + this.process = spawn("node", [this.commander.application]); + this.process.stdout.on("data", data => { + console.log(data.toString()); + }); + this.process.stderr.on("data", data => { + console.log(data.toString()); + }); + } + + restartProcess() { + if (this.process !== null) { + try { + this.process.kill("SIGKILL"); + } catch (error) { + console.log(error.message); + } + } + this.startProgress(); + } +} + +module.exports = HotLoader.getInstance(); diff --git a/bin/hotnode b/bin/hotnode new file mode 100755 index 0000000..f201623 --- /dev/null +++ b/bin/hotnode @@ -0,0 +1,23 @@ +#!/usr/bin/env node + +const fs = require("fs"); +const path = require("path"); +const commander = require("commander"); +const hotnode = require("./hotloader.js"); + +const program = new commander.Command(); + +let configData = { + application: "./index1.js", + config: "./.hotnoderc", + watch: "./" +}; + +program + .version("0.0.1") + .option("-a, --application ", "应用文件路径", configData.application) + .option("-w, --watch ", "监听变化路径", configData.watch); + +program.parse(process.argv); + +hotnode.run(program); diff --git a/bin/hotnode.js b/bin/hotnode.js deleted file mode 100644 index e69de29..0000000 diff --git a/index.js b/index.js index 2aea25c..0a1b670 100644 --- a/index.js +++ b/index.js @@ -1,31 +1,30 @@ -const os = require("os"); const http = require("http"); const config = require("./config.js"); const device = require("./device.js"); http - .createServer(async (req, res) => { - const parsedReq = device.requestParse(req), - query = Object.assign({}, config.query, parsedReq.query); - let data = {}; + .createServer(async (req, res) => { + const parsedReq = device.requestParse(req), + query = Object.assign({}, config.query, parsedReq.query); + let data = {}; - if (parsedReq.path === "/device") { - res.statusCode = 200; - res.setHeader("content-type", "application/json"); - data = await device.getData(query); - try { - data = JSON.stringify(data); - } catch (err) { - data = "{}"; - } - } else { - res.statusCode = 404; - res.setHeader("content-type", "text/html"); - res.end("

404

"); - } - res.end(data); - }) - .listen(config.server.port, config.server.host, () => { - const svr = config.server; - console.log(`server is running at ${svr.host} : ${svr.port}`); - }); + if (parsedReq.path === "/device") { + res.statusCode = 200; + res.setHeader("content-type", "application/json"); + data = await device.getData(query); + try { + data = JSON.stringify(data); + } catch (err) { + data = "{}"; + } + res.end(data); + } + + res.statusCode = 404; + res.setHeader("content-type", "text/html"); + res.end("

404

"); + }) + .listen(config.server.port, config.server.host, () => { + const svr = config.server; + console.log(`server is running at ${svr.host} : ${svr.port}`); + }); diff --git a/package.json b/package.json index f03c26d..b6c6c59 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,17 @@ { - "name": "homework-nodejs", - "version": "1.0.0", - "description": "写一个 web 服务,提供以下服务: GET 接口 `/device?pw=cpu&sort=desc`,返回:", - "main": "index.js", - "bin": { - "homework-nodejs": "hotnode.js" - }, - "scripts": { - "start": "node ./index.js", - "debug": "node --inspect-brk ./index.js" - }, - "repository": { - "type": "git", - "url": "git@github.com_qyingkou:qyingkou/homework-nodejs.git" - }, - "keywords": [], - "author": "qingkooo ", - "license": "MIT" + "name": "homework-nodejs", + "version": "1.0.0", + "description": "练习写一个接口和一个守护进程", + "scripts": { + "start": "node ./index.js", + "debug": "node --inspect-brk ./index.js", + "hot": "./bin/hotnode -a ./index.js -w ./" + }, + "repository": { + "type": "git", + "url": "git@github.com:qyingkou/homework-nodejs.git" + }, + "dependencies": { + "commander": "^2.20.0" + } } From a30f6254e87e85e5bc0bf3832a5fe273bca1cfea Mon Sep 17 00:00:00 2001 From: qingkou Date: Thu, 1 Aug 2019 23:29:21 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=94=AF=E6=8C=81watch=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/hotloader.js | 18 +++++++++++++----- package.json | 1 + 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/bin/hotloader.js b/bin/hotloader.js index 114ea8b..9cc1b85 100644 --- a/bin/hotloader.js +++ b/bin/hotloader.js @@ -1,6 +1,7 @@ const fs = require("fs"); const path = require("path"); -const { spawn } = require("child_process"); +const { spawn, exec } = require("child_process"); +const chokidar = require("chokidar"); class HotLoader { static getInstance() { @@ -13,14 +14,21 @@ class HotLoader { run(program) { this.commander = program; - fs.watch(path.resolve(this.commander.application), (event, filename) => { - this.restartProcess(); - }); + const watcher = chokidar + .watch(".", { ignored: /(^|[\/\\])\../, atomic: 500 }) + .on("change", filepath => { + console.log( + "these files has been changed:\n", + path.resolve(__dirname, filepath), + "\n" + ); + this.restartProcess(); + }); this.startProgress(); } startProgress() { - this.process = spawn("node", [this.commander.application]); + this.process = exec(`node ${this.commander.application}`); this.process.stdout.on("data", data => { console.log(data.toString()); }); diff --git a/package.json b/package.json index b6c6c59..904a500 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "url": "git@github.com:qyingkou/homework-nodejs.git" }, "dependencies": { + "chokidar": "^3.0.2", "commander": "^2.20.0" } }