Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## folders
/node_modules

## files
16 changes: 16 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -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"]
}
]
}
1 change: 0 additions & 1 deletion Readme

This file was deleted.

28 changes: 28 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# tasts

1,写一个 web 服务,提供以下服务:
GET 接口 `/device?pw=cpu&sort=desc`,返回:

```js
{
cpu:[], // 服务器cpu状态
mem:[], // 服务器内存状态
proc:[] // 全量进程列表(默认按cpu和降序排列)
}
```

2,写一个守护进程启动器:
同目录下写一个 bin/hotnode 最终通过`hotnode app.js`启动服务。
在 app.js 文件变更后自动重启 app.js 进程

## 接口

## 守护进程启动器

### 参数设计:

```cmd
// 参数说明
-a, --application <file> // 应用文件路径, "./index.js"
-w, --watch <fileOrDir> // 监听变化路径, "./");
```
52 changes: 52 additions & 0 deletions bin/hotloader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const fs = require("fs");
const path = require("path");
const { spawn, exec } = require("child_process");
const chokidar = require("chokidar");

class HotLoader {
static getInstance() {
if (!HotLoader.instance) {
HotLoader.instance = new HotLoader();
}
return HotLoader.instance;
}
constructor() {}

run(program) {
this.commander = program;
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 = exec(`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();
23 changes: 23 additions & 0 deletions bin/hotnode
Original file line number Diff line number Diff line change
@@ -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 <file>", "应用文件路径", configData.application)
.option("-w, --watch <fileOrDir>", "监听变化路径", configData.watch);

program.parse(process.argv);

hotnode.run(program);
13 changes: 13 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
@@ -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 // 显示条数
}
};
68 changes: 68 additions & 0 deletions device.js
Original file line number Diff line number Diff line change
@@ -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
};
30 changes: 30 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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 = "{}";
}
res.end(data);
}

res.statusCode = 404;
res.setHeader("content-type", "text/html");
res.end("<h1>404</h1>");
})
.listen(config.server.port, config.server.host, () => {
const svr = config.server;
console.log(`server is running at ${svr.host} : ${svr.port}`);
});
18 changes: 18 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"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": {
"chokidar": "^3.0.2",
"commander": "^2.20.0"
}
}