2022-05-11 16:20:23 +08:00

212 lines
7.1 KiB
JavaScript

const express = require('express');
const router = express.Router();
const fs = require('fs');
const path = require('path');
const process = require('child_process');
const projectsFile = path.join(__dirname, 'project')
const getDatetime = (fmt = "YYYY-mm-dd HH:MM", date) => {
date = date || new Date();
let ret;
const opt = {
"Y+": date.getFullYear().toString(), // 年
"m+": (date.getMonth() + 1).toString(), // 月
"d+": date.getDate().toString(), // 日
"H+": date.getHours().toString(), // 时
"M+": date.getMinutes().toString(), // 分
"S+": date.getSeconds().toString() // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
}
}
;
return fmt;
}
router.get('/', function (req, res, next) {
const data = fs.readFileSync(projectsFile + '/index.json');
res.json(JSON.parse(data.toString()))
});
router.get('/history', (req, res, next) => {
let {id, time} = req.query;
const fileName = projectsFile + '/' + id + '/' + time + '.log';
if (!fs.existsSync(fileName)) {
res.json({code: 1, message: "日志不存在", fileName});
return;
}
res.sendFile(fileName, {}, function (err) {
if (err) {
next(err);
}
});
});
// 读取编译记录
router.get('/:id', function (req, res, next) {
const id = req.params.id;
const file = projectsFile + '/' + id + '/index.json';
if (!fs.existsSync(file)) {
res.json({code: 1, message: "项目不存在"});
return;
}
const data = fs.readFileSync(file);
res.json(JSON.parse(data.toString()))
});
router.get('/shell/:id', (req, res) => {
const path = projectsFile + '/' + req.params.id + '/build.sh';
if (!fs.existsSync(path)) {
res.send({code: 1, message: '脚本文件不存在'})
return;
}
const shell = fs.readFileSync(path,{encoding:'utf-8'})
res.send({code: 0, shell})
});
router.post('/shell/:id', (req, res) => {
const path = projectsFile + '/' + req.params.id + '/build.sh';
if (!fs.existsSync(path)) {
res.send({code: 1, message: '脚本文件文件不存在'})
return;
}
const shell = req.body.shell;
fs.writeFileSync(path, shell,{encoding:"utf-8"})
res.send({code: 0})
});
const writeExecLog = (id, status, running = false) => {
const data = JSON.parse(fs.readFileSync(projectsFile + '/index.json'));
data[id - 1].lastUpdate = getDatetime('YYYY-mm-dd HH:MM:SS');
data[id - 1].lastStatus = status;
data[id - 1].running = running;
fs.writeFile(projectsFile + '/index.json', JSON.stringify(data), (err1) => {
if (err1) {
console.log('writeExecLog:write project file fail')
}
})
}
// 执行
router.all('/hook/:id', function (req, res, next) {
const id = parseInt(req.params.id);
const projects = JSON.parse(fs.readFileSync(projectsFile + '/index.json',{encoding:'utf-8'}));
if (id < 1 || id > projects.length) {
res.json({code: 1, message: "项目不存在(1)"});
return;
}
if (projects[id - 1].running) {
res.json({code: 3, message: "当前项目脚本正在运行中"});
return;
}
const file = projectsFile + '/' + id + '/build.sh';
if (!fs.existsSync(file)) {
res.json({code: 1, message: "项目不存在(2)"});
return;
}
res.json({code: 0, message: "开始执行脚本,请稍后查看运行结果"});
// 历史记录
fs.readFile(projectsFile + '/' + id + '/index.json', (err, data) => {
if (err) {
console.log('read project {', id, '} history failed', err)
return;
}
const histories = JSON.parse(data.toString());
const currentTime = getDatetime('YYYY-mm-dd HH:MM:SS'),timeNow = Date.now();
// 开始执行脚本
fs.open(projectsFile + '/' + id + '/' + timeNow + '.log', 'a', function (err, fd) {
if (err) { // 操作日志失败了
writeExecLog(id, 'fail');
return;
}
writeExecLog(id, null, true); // 运行中
let isFailed = -1;
const workerProcess = process.spawn('sh', [file]);
let startTime = Date.now(); // 记录开始时间
workerProcess.stdout.on('data', (execData) => {
let line = execData.toString().trim();
console.log('out:', line);
if (line == 'execute success') {
isFailed = 1;
} else if (line == 'execute fail') {
isFailed = 0;
}
fs.writeSync(fd, line); // 写入日志
});
workerProcess.stderr.on('data', (execData) => {
console.log('err:', execData.toString())
fs.writeSync(fd, execData.toString()); // 写入日志
// isFailed = true;
});
workerProcess.on('close', function (code) {
// 计算使用时间
const useTime = Date.now() - startTime;
let status = isFailed == -1 ? '未知' : (isFailed == 1 ? '成功' : '失败');
histories.push({
time: currentTime,
timestamp:timeNow,
status,
useTime
})
// 写入记录
fs.writeFileSync(projectsFile + '/' + id + '/index.json', JSON.stringify(histories));
writeExecLog(id, status)
fs.close(fd, function (err) {
if (err) {
console.log('close file error', err);
}
});
});
});
});
});
//创建项目
router.post('/create', (req, res, next) => {
const data = JSON.parse(fs.readFileSync(projectsFile + '/index.json'));
let id = data.length + 1;
let {name, shell} = req.body;
if (!name || !shell) {
res.json({code: 1, message: "参数不能为空"})
return;
}
fs.mkdirSync(projectsFile + '/' + id); // 创建项目目录
// 创建记录文件
fs.writeFile(projectsFile + '/' + id + '/index.json', '[]', function (err) {
fs.writeFile(projectsFile + '/' + id + '/build.sh', shell, (err1) => {
if (err1) {
console.log('create shell success')
}
});
if (err) {
res.json({code: 2, message: "创建项目失败"})
}
data.push({
id,
name,
create: getDatetime(),
lastUpdate: null,
lastStatus: "",
running: false
})
fs.writeFile(projectsFile + '/index.json', JSON.stringify(data), (err1) => {
if (err1) {
console.log('create project fail')
}
})
res.json(data);
});
});
module.exports = router;