diff --git a/ksr.js b/ksr.js new file mode 100644 index 0000000..7a1bf55 --- /dev/null +++ b/ksr.js @@ -0,0 +1,51 @@ +import { spawn } from 'child_process'; +import log4js from 'log4js'; +import http from 'http' + +/* keep ssh run */ + +log4js.configure({ + appenders: { console: { type: 'console' } }, + categories: { default: { appenders: ['console'], level: 'debug' } } +}); +const logger = log4js.getLogger('app'); + +let serverProcess; +const startServer = async () => { + logger.info('Starting Bot...'); + serverProcess = spawn('node', ['app.js'], { stdio: 'inherit' }); + serverProcess.on('close', (code) => { + logger.info(`Bot process exited with code ${code}`); + if (code == null) return + process.exit() + }); +}; +startServer(); + +const serverHttpexit = http.createServer(async (req, res) => { + let remoteIP = req.socket.remoteAddress; + if (remoteIP.startsWith('::ffff:')) { + remoteIP = remoteIP.slice(7); + } + if (remoteIP !== `::1` && remoteIP !== `127.0.0.1`) { + console.log(remoteIP) + res.writeHead(403, { 'Content-Type': 'text/plain' }); + res.end('Access Forbidden\n'); + return + } + if (req.url === `/restart`) { + await serverProcess.kill(); + await startServer(); + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end('OK\n'); + } else if (req.url === `/exit`) { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end('OK\n'); + process.exit() + } else { + res.writeHead(404, { 'Content-Type': 'text/plain' }); + res.end('Not Found\n'); + } +}) + +serverHttpexit.listen(27881, () => { }); diff --git a/plugins/other/restart.js b/plugins/other/restart.js index fb7d077..191540f 100644 --- a/plugins/other/restart.js +++ b/plugins/other/restart.js @@ -1,9 +1,20 @@ 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({ @@ -62,30 +73,44 @@ export class Restart extends plugin { }) let npm = await this.checkPnpm() - - try { - await redis.set(this.key, data, { EX: 120 }) - let cm = `${npm} start` - if (process.argv[1].includes('pm2')) { - cm = `${npm} run restart` - } - - exec(cm, { windowsHide: true }, (error, stdout, stderr) => { - if (error) { + 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(`操作失败!\n${error.stack}`) - logger.error(`重启失败\n${error.stack}`) - } else if (stdout) { - logger.mark('重启成功,运行已由前台转为后台') - logger.mark(`查看日志请用命令:${npm} run log`) - logger.mark(`停止后台运行命令:${npm} stop`) - process.exit() + this.e.reply(`操作失败!`) + logger.error(`重启失败`) } - }) - } catch (error) { - redis.del(this.key) - let e = error.stack ?? error - this.e.reply(`操作失败!\n${e}`) + } 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 @@ -107,6 +132,18 @@ export class Restart extends plugin { } 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('关机成功,已停止运行')