Miao-Yunzai/plugins/other/restart.js

165 lines
4.5 KiB
JavaScript

import plugin from '../../lib/plugins/plugin.js'
import { createRequire } from 'module'
import fetch from 'node-fetch'
import net from 'net'
const require = createRequire(import.meta.url)
const { exec } = require('child_process')
const isPortTaken = async (port) => {
return new Promise((resolve) => {
const tester = net.createServer()
.once('error', () => resolve(true))
.once('listening', () => tester.once('close', () => resolve(false)).close())
.listen(port);
});
};
export class Restart extends plugin {
constructor (e = '') {
super({
name: '重启',
dsc: '#重启',
event: 'message',
priority: 10,
rule: [{
reg: '^#重启$',
fnc: 'restart',
permission: 'master'
}, {
reg: '^#(停机|关机)$',
fnc: 'stop',
permission: 'master'
}]
})
if (e) this.e = e
this.key = 'Yz:restart'
}
async init () {
let restart = await redis.get(this.key)
if (restart) {
restart = JSON.parse(restart)
const uin = restart?.uin || Bot.uin
let time = restart.time || new Date().getTime()
time = (new Date().getTime() - time) / 1000
let msg = `重启成功:耗时${time.toFixed(2)}`
try {
if (restart.isGroup) {
Bot[uin].pickGroup(restart.id).sendMsg(msg)
} else {
Bot[uin].pickUser(restart.id).sendMsg(msg)
}
} catch (error) {
/** 不发了,发不出去... */
logger.debug(error)
}
redis.del(this.key)
}
}
async restart () {
await this.e.reply('开始执行重启,请稍等...')
logger.mark(`${this.e.logFnc} 开始执行重启,请稍等...`)
let data = JSON.stringify({
uin: this.e?.self_id || this.e.bot.uin,
isGroup: !!this.e.isGroup,
id: this.e.isGroup ? this.e.group_id : this.e.user_id,
time: new Date().getTime()
})
let npm = await this.checkPnpm()
await redis.set(this.key, data, { EX: 120 })
if(await isPortTaken(27881)) {
try {
let result = await fetch(`http://localhost:27881/restart`)
result = await result.text()
if(result !== `OK`) {
redis.del(this.key)
this.e.reply(`操作失败!`)
logger.error(`重启失败`)
}
} catch(error) {
redis.del(this.key)
this.e.reply(`操作失败!\n${error}`)
}
} else {
try {
let cm = `${npm} start`
if (process.argv[1].includes('pm2')) {
cm = `${npm} run restart`
}
exec(cm, { windowsHide: true }, (error, stdout, stderr) => {
if (error) {
redis.del(this.key)
this.e.reply(`操作失败!\n${error.stack}`)
logger.error(`重启失败\n${error.stack}`)
} else if (stdout) {
logger.mark('重启成功,运行已由前台转为后台')
logger.mark(`查看日志请用命令:${npm} run log`)
logger.mark(`停止后台运行命令:${npm} stop`)
process.exit()
}
})
} catch (error) {
redis.del(this.key)
let e = error.stack ?? error
this.e.reply(`操作失败!\n${e}`)
}
}
return true
}
async checkPnpm () {
let npm = 'npm'
let ret = await this.execSync('pnpm -v')
if (ret.stdout) npm = 'pnpm'
return npm
}
async execSync (cmd) {
return new Promise((resolve, reject) => {
exec(cmd, { windowsHide: true }, (error, stdout, stderr) => {
resolve({ error, stdout, stderr })
})
})
}
async stop () {
if(await isPortTaken(27881)) {
try {
logger.mark('关机成功,已停止运行')
await this.e.reply(`关机成功,已停止运行`)
await fetch(`http://localhost:27881/exit`)
return
} catch(error) {
this.e.reply(`操作失败!\n${error}`)
logger.error(`关机失败\n${error}`)
}
}
if (!process.argv[1].includes('pm2')) {
logger.mark('关机成功,已停止运行')
await this.e.reply('关机成功,已停止运行')
process.exit()
}
logger.mark('关机成功,已停止运行')
await this.e.reply('关机成功,已停止运行')
let npm = await this.checkPnpm()
exec(`${npm} stop`, { windowsHide: true }, (error, stdout, stderr) => {
if (error) {
this.e.reply(`操作失败!\n${error.stack}`)
logger.error(`关机失败\n${error.stack}`)
}
})
}
}