You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
4.8 KiB
162 lines
4.8 KiB
const {koaBody} = require('koa-body');
|
|
const Koa = require('koa');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { spawn } = require('child_process')
|
|
const router = require('koa-router')()
|
|
, os = require('os')
|
|
, iconv = require("iconv-lite")
|
|
const moment = require('moment')
|
|
|
|
const { DATABASELIST, SERVER_PORT} = require('./config')
|
|
|
|
// 备份间隔时间
|
|
const mintues = 60 * 24;// minute
|
|
|
|
|
|
|
|
// web服务
|
|
function server(){
|
|
const app = new Koa();
|
|
app.use(koaBody({
|
|
multipart: true, // 支持文件上传
|
|
formidable: {
|
|
maxFieldsSize: 500 * 1024 * 1024, // 最大文件为2兆
|
|
multipart: true // 是否支持 multipart-formdate 的表单
|
|
}
|
|
}));
|
|
router.post('/putfile', async ctx => {
|
|
const fileList = await getFileList()
|
|
console.log('请求备份', fileList)
|
|
if(fileList.length == 0){
|
|
ctx.body = [{state:false,filename:'无备份文件'}]
|
|
}else{
|
|
const bunneryList = await readFile(fileList)
|
|
ctx.body = bunneryList
|
|
deleteFile(fileList)
|
|
}
|
|
});
|
|
app.use(router.routes(), router.allowedMethods())
|
|
app.listen(SERVER_PORT, () => {
|
|
console.log('=> 备份服务已启动! http://127.0.0.1:' + SERVER_PORT)
|
|
});
|
|
}
|
|
|
|
// 本分服务
|
|
function back(){
|
|
/**
|
|
* 数据库备份程序
|
|
* */
|
|
function backSQL(host, user, passwd, database){
|
|
return new Promise(rec => {
|
|
const cout = os.platform() == 'win32' ? '-r' : '>'
|
|
, filename = `back/BACKUP_${ database }_${ moment().format("YYYY_MM_DD_HH_mm_ss") }.sql`
|
|
const backProcess = spawn('mysqldump',['-u'+user, '-p'+passwd, database, cout + filename]);
|
|
backProcess.stdout.on('data', data => console.log('Data : ', out(data)))
|
|
backProcess.stderr.on('data', data => console.log('Error: ', out(data)))
|
|
backProcess.on('close', code => {
|
|
console.log('Exit :', code.toString())
|
|
rec(filename)
|
|
})
|
|
})
|
|
}
|
|
|
|
// 开始备份数据库
|
|
function startBackSQL(){
|
|
// 数据库信息
|
|
let host = "localhost"
|
|
, user = "root"
|
|
, passwd = "root"
|
|
, database = "develop"
|
|
backSQL(host, user, passwd, database)
|
|
const outTime = getT() - new Date().getTime()
|
|
for(let item in DATABASELIST){
|
|
const i = DATABASELIST[item];
|
|
database = i;
|
|
setTimeout(() => {
|
|
setInterval(() => {
|
|
backSQL(host, user, passwd, database)
|
|
}, 1000 * 60 * mintues)
|
|
},outTime)
|
|
}
|
|
}
|
|
/**
|
|
* 根据系统类型,读取编码格式
|
|
* */
|
|
function out(data){
|
|
if(os.platform() == 'win32'){
|
|
return iconv.decode(data, 'GBK')
|
|
}else{
|
|
return data
|
|
}
|
|
}
|
|
|
|
// 读取文件目录
|
|
function getFileList(){
|
|
return new Promise((rec, res) => {
|
|
fs.readdir(__dirname + '/back', (err, fileList) => {
|
|
if(err){
|
|
res(err)
|
|
}else{
|
|
rec(fileList)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// 读取文件
|
|
function readFile(fileList){
|
|
return new Promise(rec => {
|
|
const list = []
|
|
for(let i in fileList){
|
|
fs.readFile(__dirname + '/back/' + fileList[i],'utf8',function(err,datastr){
|
|
if(err){
|
|
list.push({
|
|
state:false,
|
|
filename:fileList[i]
|
|
})
|
|
}else{
|
|
list.push({
|
|
state:true,
|
|
filename:fileList[i],
|
|
file:datastr
|
|
})
|
|
}
|
|
if(i == fileList.length -1){
|
|
rec(list)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
// 删除文件
|
|
function deleteFile(filelist){
|
|
for(let filename of filelist){
|
|
fs.unlink(__dirname + '/back/' + filename, (e, data) => {
|
|
if(e){
|
|
console.log('删除文件失败:', filename)
|
|
}else{
|
|
console.log('删除文件成功:', filename)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// 获取明天凌晨时间
|
|
function getT(){
|
|
const temore = new Date().getTime() + 1000 * 60 * 60 * 24
|
|
const now = new Date(temore)
|
|
let year = now.getFullYear(); //得到年份
|
|
let month = now.getMonth();//得到月份
|
|
let date = now.getDate();//得到日期
|
|
return new Date(year + "-" + month + "-" + date).getTime()
|
|
}
|
|
|
|
|
|
// 启动本地备份
|
|
startBackSQL()
|
|
}
|
|
|
|
server()
|
|
back() |