refactor: 优化检查机制
This commit is contained in:
parent
4fe35676f3
commit
54aa32d0e4
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"apps": [
|
|
||||||
{
|
|
||||||
"name": "Miao-Yunzai",
|
|
||||||
"script": "./index.js",
|
|
||||||
"max_memory_restart": "512M",
|
|
||||||
"restart_delay": 60000
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,6 +1,5 @@
|
||||||
import '../src/init/modules.js'
|
|
||||||
import '../src/init/logger.js'
|
|
||||||
import '../src/init/config.js'
|
import '../src/init/config.js'
|
||||||
|
import '../src/init/logger.js'
|
||||||
import '../src/init/redis.js'
|
import '../src/init/redis.js'
|
||||||
import './tailwindcss.js'
|
import './tailwindcss.js'
|
||||||
import Koa from 'koa'
|
import Koa from 'koa'
|
||||||
|
|
|
@ -5,8 +5,24 @@ module.exports = {
|
||||||
name: 'Miao-Yunzai',
|
name: 'Miao-Yunzai',
|
||||||
script: './index.js',
|
script: './index.js',
|
||||||
args: argv,
|
args: argv,
|
||||||
max_memory_restart: '512M',
|
// 超时时间内进程仍未终止,则 PM2 将强制终止该进程
|
||||||
restart_delay: 60000
|
kill_timeout: 5000,
|
||||||
|
// 发送意外重启
|
||||||
|
autorestart: true,
|
||||||
|
// 进程到达指定内存时重启
|
||||||
|
max_memory_restart: '2G',
|
||||||
|
// 进程重启之间的延迟时间
|
||||||
|
restart_delay: 5000,
|
||||||
|
// 进程重启之间的最大延迟时间
|
||||||
|
restart_delay_max: 10000,
|
||||||
|
// 将 PM2 进程列表自动保存到文件中
|
||||||
|
autodump: true,
|
||||||
|
// 不监听文件变化
|
||||||
|
watch: false,
|
||||||
|
env: {
|
||||||
|
NODE_ENV: 'production'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
console.log('module.exports', module.exports)
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
import { execAsync, readJSON } from "./utils.js"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验运行
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export async function checkRun() {
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
if (process.argv[1].includes('pm2')) return
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
if (process.argv[1].includes('test')) return
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
const cfg = readJSON('./config/pm2/pm2.json')
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
if (!cfg) return
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
execAsync(`pm2 show ${cfg.apps[0].name}`).then((status) => {
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
if (status.stdout.includes('online')) {
|
|
||||||
logger.mark('检测到后台正在运行')
|
|
||||||
logger.mark('已停止后台进程,防止重复运行')
|
|
||||||
execAsync(`pm2 stop ${cfg.apps[0].name}`).catch(logger.error)
|
|
||||||
}
|
|
||||||
}).catch(() => { })
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
import log4js from 'log4js'
|
|
||||||
import chalk from 'chalk'
|
|
||||||
import cfg from './config.js'
|
|
||||||
import { mkdirSync } from 'node:fs'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建日志
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function createLog() {
|
|
||||||
// log4js.levels.levels[5].level = Number.MAX_VALUE
|
|
||||||
// log4js.levels.levels.sort((a, b) => a.level - b.level)
|
|
||||||
log4js.configure({
|
|
||||||
appenders: {
|
|
||||||
console: {
|
|
||||||
type: 'console',
|
|
||||||
layout: {
|
|
||||||
type: 'pattern',
|
|
||||||
pattern: '%[[MYZ-V4][%d{hh:mm:ss.SSS}][%4.4p]%] %m'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
command: {
|
|
||||||
type: 'dateFile', // 可以是console,dateFile,file,Logstash等
|
|
||||||
filename: 'logs/command', // 将会按照filename和pattern拼接文件名
|
|
||||||
pattern: 'yyyy-MM-dd.log',
|
|
||||||
numBackups: 15,
|
|
||||||
alwaysIncludePattern: true,
|
|
||||||
layout: {
|
|
||||||
type: 'pattern',
|
|
||||||
pattern: '[%d{hh:mm:ss.SSS}][%4.4p] %m'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
type: 'file',
|
|
||||||
filename: 'logs/error.log',
|
|
||||||
alwaysIncludePattern: true,
|
|
||||||
layout: {
|
|
||||||
type: 'pattern',
|
|
||||||
pattern: '[%d{hh:mm:ss.SSS}][%4.4p] %m'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
categories: {
|
|
||||||
default: { appenders: ['console'], level: cfg.bot.log_level },
|
|
||||||
command: { appenders: ['console', 'command'], level: 'warn' },
|
|
||||||
error: { appenders: ['console', 'command', 'error'], level: 'error' }
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const defaultLogger = log4js.getLogger('message')
|
|
||||||
const commandLogger = log4js.getLogger('command')
|
|
||||||
const errorLogger = log4js.getLogger('error')
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 调整error日志等级
|
|
||||||
*/
|
|
||||||
const logger = {
|
|
||||||
trace() {
|
|
||||||
defaultLogger.trace.call(defaultLogger, ...arguments)
|
|
||||||
},
|
|
||||||
debug() {
|
|
||||||
defaultLogger.debug.call(defaultLogger, ...arguments)
|
|
||||||
},
|
|
||||||
info() {
|
|
||||||
defaultLogger.info.call(defaultLogger, ...arguments)
|
|
||||||
},
|
|
||||||
// warn及以上的日志采用error策略
|
|
||||||
warn() {
|
|
||||||
commandLogger.warn.call(defaultLogger, ...arguments)
|
|
||||||
},
|
|
||||||
error() {
|
|
||||||
errorLogger.error.call(errorLogger, ...arguments)
|
|
||||||
},
|
|
||||||
fatal() {
|
|
||||||
errorLogger.fatal.call(errorLogger, ...arguments)
|
|
||||||
},
|
|
||||||
mark() {
|
|
||||||
errorLogger.mark.call(commandLogger, ...arguments)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return logger
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置日志样式
|
|
||||||
*/
|
|
||||||
export function loggerInit() {
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
mkdirSync('./logs', {
|
|
||||||
'recursive': true
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 全局变量 logger
|
|
||||||
*/
|
|
||||||
global.logger = createLog() as any
|
|
||||||
logger.chalk = chalk
|
|
||||||
logger.red = chalk.red
|
|
||||||
logger.green = chalk.green
|
|
||||||
logger.yellow = chalk.yellow
|
|
||||||
logger.blue = chalk.blue
|
|
||||||
logger.magenta = chalk.magenta
|
|
||||||
logger.cyan = chalk.cyan
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
import cfg from "./config.js"
|
|
||||||
import { execAsync, sleep } from "./utils.js"
|
|
||||||
import { createClient } from "redis"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化全局redis客户端
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export async function redisInit() {
|
|
||||||
const rc = cfg.redis
|
|
||||||
const redisUn = rc.username || ""
|
|
||||||
let redisPw = rc.password ? `:${rc.password}` : ""
|
|
||||||
if (rc.username || rc.password) {
|
|
||||||
redisPw += "@"
|
|
||||||
}
|
|
||||||
const redisUrl = `redis://${redisUn}${redisPw}${rc.host}:${rc.port}/${rc.db}`
|
|
||||||
let client = createClient({ url: redisUrl })
|
|
||||||
|
|
||||||
try {
|
|
||||||
logger.info(`正在连接 ${logger.blue(redisUrl)}`)
|
|
||||||
await client.connect()
|
|
||||||
} catch (err) {
|
|
||||||
logger.error(`Redis 错误:${logger.red(err)}`)
|
|
||||||
|
|
||||||
const cmd = "redis-server --save 900 1 --save 300 10 --daemonize yes" + await aarch64()
|
|
||||||
logger.info("正在启动 Redis...")
|
|
||||||
|
|
||||||
await execAsync(cmd)
|
|
||||||
|
|
||||||
await sleep(1000)
|
|
||||||
|
|
||||||
try {
|
|
||||||
client = createClient({ url: redisUrl })
|
|
||||||
await client.connect()
|
|
||||||
} catch (err) {
|
|
||||||
logger.error(`Redis 错误:${logger.red(err)}`)
|
|
||||||
logger.error(`请先启动 Redis:${logger.blue(cmd)}`)
|
|
||||||
process.exit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
client.on("error", async err => {
|
|
||||||
logger.error(`Redis 错误:${logger.red(err)}`)
|
|
||||||
const cmd = "redis-server --save 900 1 --save 300 10 --daemonize yes" + await aarch64()
|
|
||||||
logger.error(`请先启动 Redis:${cmd}`)
|
|
||||||
process.exit()
|
|
||||||
})
|
|
||||||
|
|
||||||
/** 全局变量 redis */
|
|
||||||
global.redis = client as any
|
|
||||||
|
|
||||||
logger.info("Redis 连接成功")
|
|
||||||
return client
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async function aarch64() {
|
|
||||||
if (process.platform == "win32") return ""
|
|
||||||
return await execAsync("uname -m").then(async arch => {
|
|
||||||
if (arch.stdout && arch.stdout.includes("aarch64")) {
|
|
||||||
/** 判断redis版本 */
|
|
||||||
let v = await execAsync("redis-server -v")
|
|
||||||
if (v.stdout) {
|
|
||||||
const data = v.stdout.match(/v=(\d)./)
|
|
||||||
/** 忽略arm警告 */
|
|
||||||
if (data && Number(data[1]) >= 6) {
|
|
||||||
return " --ignore-warnings ARM64-COW-BUG"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,7 +1,3 @@
|
||||||
import fs from 'node:fs'
|
|
||||||
import { exec } from 'child_process'
|
|
||||||
import { join } from 'path'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 休眠函数
|
* 休眠函数
|
||||||
* @param ms 毫秒
|
* @param ms 毫秒
|
||||||
|
@ -9,34 +5,3 @@ import { join } from 'path'
|
||||||
export function sleep(ms: number) {
|
export function sleep(ms: number) {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param cmd
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function execAsync(cmd: string): Promise<{
|
|
||||||
stdout: string
|
|
||||||
stderr: string
|
|
||||||
}> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
exec(cmd, (error, stdout, stderr) => {
|
|
||||||
if (error) reject(error)
|
|
||||||
resolve({ stdout, stderr })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param dir
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function readJSON(dir: string) {
|
|
||||||
try {
|
|
||||||
const cfg = fs.readFileSync(join(process.cwd(), dir), 'utf-8')
|
|
||||||
return JSON.parse(cfg)
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
103
src/init.ts
103
src/init.ts
|
@ -1,104 +1,5 @@
|
||||||
import './init/modules.js'
|
|
||||||
import './init/config.js'
|
import './init/config.js'
|
||||||
import './init/logger.js'
|
import './init/logger.js'
|
||||||
import './init/redis.js'
|
import './init/redis.js'
|
||||||
import { promises } from 'node:fs'
|
import './init/process.js'
|
||||||
import yaml from 'yaml'
|
import './init/run.js'
|
||||||
import { BOT_NAME } from './config'
|
|
||||||
import { CONFIG_INIT_PATH } from './config/system.js'
|
|
||||||
import { checkRun } from './config/check.js'
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
logger.mark(`${BOT_NAME} 启动中...`)
|
|
||||||
/**
|
|
||||||
* 设置标题
|
|
||||||
*/
|
|
||||||
process.title = BOT_NAME
|
|
||||||
/**
|
|
||||||
* 设置时区
|
|
||||||
*/
|
|
||||||
process.env.TZ = 'Asia/Shanghai'
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
process.on('SIGHUP', () => process.exit())
|
|
||||||
/**
|
|
||||||
* 捕获未处理的错误
|
|
||||||
*/
|
|
||||||
process.on('uncaughtException', error => {
|
|
||||||
if (typeof logger == 'undefined') console.log(error)
|
|
||||||
else logger.error(error)
|
|
||||||
})
|
|
||||||
/**
|
|
||||||
* 捕获未处理的Promise错误
|
|
||||||
*/
|
|
||||||
process.on('unhandledRejection', error => {
|
|
||||||
if (typeof logger == 'undefined') console.log(error)
|
|
||||||
else logger.error(error)
|
|
||||||
})
|
|
||||||
/**
|
|
||||||
* 退出事件
|
|
||||||
*/
|
|
||||||
process.on('exit', async () => {
|
|
||||||
if (typeof redis != 'undefined') {
|
|
||||||
await redis.save()
|
|
||||||
}
|
|
||||||
if (typeof logger == 'undefined') {
|
|
||||||
console.log(`${BOT_NAME} 已停止运行`)
|
|
||||||
} else {
|
|
||||||
logger.mark(logger.magenta(`${BOT_NAME} 已停止运行`))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
/**
|
|
||||||
* 添加一些多余的标题内容
|
|
||||||
*/
|
|
||||||
let title = BOT_NAME
|
|
||||||
//
|
|
||||||
const qq = await promises
|
|
||||||
.readFile(`./${CONFIG_INIT_PATH}qq.yaml`, 'utf-8')
|
|
||||||
.then(yaml.parse)
|
|
||||||
.catch(() => null)
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
if (qq) {
|
|
||||||
title += `@${qq.qq || ''}`
|
|
||||||
switch (qq.platform) {
|
|
||||||
case 1: {
|
|
||||||
title += ' 安卓手机'
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 2: {
|
|
||||||
title += ' aPad'
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 3: {
|
|
||||||
title += ' 安卓手表'
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 4: {
|
|
||||||
title += ' MacOS'
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 5: {
|
|
||||||
title += ' iPad'
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 6: {
|
|
||||||
title += ' Tim'
|
|
||||||
break
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 设置标题
|
|
||||||
*/
|
|
||||||
process.title = title
|
|
||||||
/**
|
|
||||||
* 检查程序
|
|
||||||
*/
|
|
||||||
await checkRun()
|
|
||||||
|
|
|
@ -1,2 +1,101 @@
|
||||||
import { loggerInit } from '../config/log'
|
import log4js from 'log4js'
|
||||||
loggerInit()
|
import chalk from 'chalk'
|
||||||
|
import cfg from '../config/config.js'
|
||||||
|
import { mkdirSync } from 'node:fs'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建日志
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function createLog() {
|
||||||
|
// log4js.levels.levels[5].level = Number.MAX_VALUE
|
||||||
|
// log4js.levels.levels.sort((a, b) => a.level - b.level)
|
||||||
|
log4js.configure({
|
||||||
|
appenders: {
|
||||||
|
console: {
|
||||||
|
type: 'console',
|
||||||
|
layout: {
|
||||||
|
type: 'pattern',
|
||||||
|
pattern: '%[[MYZ-V4][%d{hh:mm:ss.SSS}][%4.4p]%] %m'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
command: {
|
||||||
|
type: 'dateFile', // 可以是console,dateFile,file,Logstash等
|
||||||
|
filename: 'logs/command', // 将会按照filename和pattern拼接文件名
|
||||||
|
pattern: 'yyyy-MM-dd.log',
|
||||||
|
numBackups: 15,
|
||||||
|
alwaysIncludePattern: true,
|
||||||
|
layout: {
|
||||||
|
type: 'pattern',
|
||||||
|
pattern: '[%d{hh:mm:ss.SSS}][%4.4p] %m'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
type: 'file',
|
||||||
|
filename: 'logs/error.log',
|
||||||
|
alwaysIncludePattern: true,
|
||||||
|
layout: {
|
||||||
|
type: 'pattern',
|
||||||
|
pattern: '[%d{hh:mm:ss.SSS}][%4.4p] %m'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
categories: {
|
||||||
|
default: { appenders: ['console'], level: cfg.bot.log_level },
|
||||||
|
command: { appenders: ['console', 'command'], level: 'warn' },
|
||||||
|
error: { appenders: ['console', 'command', 'error'], level: 'error' }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const defaultLogger = log4js.getLogger('message')
|
||||||
|
const commandLogger = log4js.getLogger('command')
|
||||||
|
const errorLogger = log4js.getLogger('error')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调整error日志等级
|
||||||
|
*/
|
||||||
|
const logger = {
|
||||||
|
trace() {
|
||||||
|
defaultLogger.trace.call(defaultLogger, ...arguments)
|
||||||
|
},
|
||||||
|
debug() {
|
||||||
|
defaultLogger.debug.call(defaultLogger, ...arguments)
|
||||||
|
},
|
||||||
|
info() {
|
||||||
|
defaultLogger.info.call(defaultLogger, ...arguments)
|
||||||
|
},
|
||||||
|
// warn及以上的日志采用error策略
|
||||||
|
warn() {
|
||||||
|
commandLogger.warn.call(defaultLogger, ...arguments)
|
||||||
|
},
|
||||||
|
error() {
|
||||||
|
errorLogger.error.call(errorLogger, ...arguments)
|
||||||
|
},
|
||||||
|
fatal() {
|
||||||
|
errorLogger.fatal.call(errorLogger, ...arguments)
|
||||||
|
},
|
||||||
|
mark() {
|
||||||
|
errorLogger.mark.call(commandLogger, ...arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
mkdirSync('./logs', {
|
||||||
|
recursive: true
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局变量 logger
|
||||||
|
*/
|
||||||
|
global.logger = createLog() as any
|
||||||
|
logger.chalk = chalk
|
||||||
|
logger.red = chalk.red
|
||||||
|
logger.green = chalk.green
|
||||||
|
logger.yellow = chalk.yellow
|
||||||
|
logger.blue = chalk.blue
|
||||||
|
logger.magenta = chalk.magenta
|
||||||
|
logger.cyan = chalk.cyan
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
import { existsSync } from 'fs'
|
|
||||||
import { join } from 'path'
|
|
||||||
const node_modules = join(process.cwd(), './node_modules')
|
|
||||||
/**
|
|
||||||
* 检查node_modules
|
|
||||||
*/
|
|
||||||
if (!existsSync(node_modules)) {
|
|
||||||
console.log('未安装依赖。。。。')
|
|
||||||
console.log('请先运行命令:pnpm install -P 安装依赖')
|
|
||||||
process.exit()
|
|
||||||
}
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
import { promises } from 'node:fs'
|
||||||
|
import yaml from 'yaml'
|
||||||
|
import { BOT_NAME, CONFIG_INIT_PATH } from '../config/system.js'
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
logger.mark(`${BOT_NAME} 启动中...`)
|
||||||
|
/**
|
||||||
|
* 设置标题
|
||||||
|
*/
|
||||||
|
process.title = BOT_NAME
|
||||||
|
/**
|
||||||
|
* 设置时区
|
||||||
|
*/
|
||||||
|
process.env.TZ = 'Asia/Shanghai'
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
process.on('SIGHUP', () => process.exit())
|
||||||
|
/**
|
||||||
|
* 捕获未处理的错误
|
||||||
|
*/
|
||||||
|
process.on('uncaughtException', error => {
|
||||||
|
if (typeof logger == 'undefined') console.log(error)
|
||||||
|
else logger.error(error)
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* 捕获未处理的Promise错误
|
||||||
|
*/
|
||||||
|
process.on('unhandledRejection', error => {
|
||||||
|
if (typeof logger == 'undefined') console.log(error)
|
||||||
|
else logger.error(error)
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* 退出事件
|
||||||
|
*/
|
||||||
|
process.on('exit', async () => {
|
||||||
|
if (typeof redis != 'undefined') {
|
||||||
|
await redis.save()
|
||||||
|
}
|
||||||
|
if (typeof logger == 'undefined') {
|
||||||
|
console.log(`${BOT_NAME} 已停止运行`)
|
||||||
|
} else {
|
||||||
|
logger.mark(logger.magenta(`${BOT_NAME} 已停止运行`))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* 添加一些多余的标题内容
|
||||||
|
*/
|
||||||
|
let title = BOT_NAME
|
||||||
|
//
|
||||||
|
const qq = await promises
|
||||||
|
.readFile(`./${CONFIG_INIT_PATH}qq.yaml`, 'utf-8')
|
||||||
|
.then(yaml.parse)
|
||||||
|
.catch(() => null)
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (qq) {
|
||||||
|
title += `@${qq.qq || ''}`
|
||||||
|
switch (qq.platform) {
|
||||||
|
case 1: {
|
||||||
|
title += ' 安卓手机'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
title += ' aPad'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
title += ' 安卓手表'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
title += ' MacOS'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 5: {
|
||||||
|
title += ' iPad'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 6: {
|
||||||
|
title += ' Tim'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 设置标题
|
||||||
|
*/
|
||||||
|
process.title = title
|
|
@ -1,2 +1,71 @@
|
||||||
import { redisInit } from '../config/redis'
|
import cfg from '../config/config.js'
|
||||||
|
import { execAsync, sleep } from '../utils/common.js'
|
||||||
|
import { createClient } from 'redis'
|
||||||
|
/**
|
||||||
|
* 初始化全局redis客户端
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function redisInit() {
|
||||||
|
const rc = cfg.redis
|
||||||
|
const redisUn = rc.username || ''
|
||||||
|
let redisPw = rc.password ? `:${rc.password}` : ''
|
||||||
|
if (rc.username || rc.password) {
|
||||||
|
redisPw += '@'
|
||||||
|
}
|
||||||
|
const redisUrl = `redis://${redisUn}${redisPw}${rc.host}:${rc.port}/${rc.db}`
|
||||||
|
let client = createClient({ url: redisUrl })
|
||||||
|
try {
|
||||||
|
logger.info(`正在连接 ${logger.blue(redisUrl)}`)
|
||||||
|
await client.connect()
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`Redis 错误:${logger.red(err)}`)
|
||||||
|
const cmd =
|
||||||
|
'redis-server --save 900 1 --save 300 10 --daemonize yes' +
|
||||||
|
(await aarch64())
|
||||||
|
logger.info('正在启动 Redis...')
|
||||||
|
await execAsync(cmd)
|
||||||
|
await sleep(1000)
|
||||||
|
try {
|
||||||
|
client = createClient({ url: redisUrl })
|
||||||
|
await client.connect()
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`Redis 错误:${logger.red(err)}`)
|
||||||
|
logger.error(`请先启动 Redis:${logger.blue(cmd)}`)
|
||||||
|
process.exit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.on('error', async err => {
|
||||||
|
logger.error(`Redis 错误:${logger.red(err)}`)
|
||||||
|
const cmd =
|
||||||
|
'redis-server --save 900 1 --save 300 10 --daemonize yes' +
|
||||||
|
(await aarch64())
|
||||||
|
logger.error(`请先启动 Redis:${cmd}`)
|
||||||
|
process.exit()
|
||||||
|
})
|
||||||
|
/** 全局变量 redis */
|
||||||
|
global.redis = client as any
|
||||||
|
logger.info('Redis 连接成功')
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function aarch64() {
|
||||||
|
if (process.platform == 'win32') return ''
|
||||||
|
return await execAsync('uname -m').then(async arch => {
|
||||||
|
if (arch.stdout && arch.stdout.includes('aarch64')) {
|
||||||
|
/** 判断redis版本 */
|
||||||
|
let v = await execAsync('redis-server -v')
|
||||||
|
if (v.stdout) {
|
||||||
|
const data = v.stdout.match(/v=(\d)./)
|
||||||
|
/** 忽略arm警告 */
|
||||||
|
if (data && Number(data[1]) >= 6) {
|
||||||
|
return ' --ignore-warnings ARM64-COW-BUG'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
}
|
||||||
await redisInit()
|
await redisInit()
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { join } from 'path'
|
||||||
|
import { createRequire } from 'module'
|
||||||
|
import { existsSync } from 'fs'
|
||||||
|
import pm2 from 'pm2'
|
||||||
|
const require = createRequire(import.meta.url)
|
||||||
|
/**
|
||||||
|
* 校验运行
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function checkRun() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (process.argv[1].includes('pm2')) {
|
||||||
|
resolve(true)
|
||||||
|
}
|
||||||
|
if (process.argv[1].includes('test')) {
|
||||||
|
resolve(true)
|
||||||
|
}
|
||||||
|
// 不是生产运行
|
||||||
|
if (process.env.NODE_ENV != 'production') {
|
||||||
|
const dir = join(process.cwd(), 'pm2.config.cjs')
|
||||||
|
if (!existsSync(dir)) {
|
||||||
|
reject(false)
|
||||||
|
}
|
||||||
|
const cfg = require('../../pm2.config.cjs')
|
||||||
|
pm2.connect(err => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//
|
||||||
|
pm2.list((err, processList) => {
|
||||||
|
if (err) {
|
||||||
|
pm2.disconnect()
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const app = processList.find(p => p.name === cfg.apps[0].name)
|
||||||
|
if (app && app.pm2_env.status === 'online') {
|
||||||
|
console.log('检测到后台正在运行')
|
||||||
|
// 关闭
|
||||||
|
pm2.stop(cfg.apps[0].name, err => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
console.log('已停止后台进程,防止重复运行')
|
||||||
|
}
|
||||||
|
pm2.disconnect()
|
||||||
|
resolve(true)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 断开连接
|
||||||
|
pm2.disconnect()
|
||||||
|
resolve(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
resolve(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
await checkRun().catch(err => {
|
||||||
|
// 打印错误
|
||||||
|
console.error(err)
|
||||||
|
// 关闭进程
|
||||||
|
process.exit(2)
|
||||||
|
})
|
109
trss.js
109
trss.js
|
@ -1,109 +0,0 @@
|
||||||
console.log("正迁移到 TRSS-Yunzai")
|
|
||||||
|
|
||||||
import fs from "node:fs"
|
|
||||||
import { execSync } from "child_process"
|
|
||||||
import YAML from "yaml"
|
|
||||||
|
|
||||||
function exec(cmd) { try {
|
|
||||||
console.log(`执行命令 [${cmd}]`)
|
|
||||||
console.log(execSync(cmd).toString())
|
|
||||||
return true
|
|
||||||
} catch (err) {
|
|
||||||
console.error("执行", cmd, "失败", err)
|
|
||||||
return false
|
|
||||||
}}
|
|
||||||
|
|
||||||
function rm(file) { try {
|
|
||||||
if (!fs.existsSync(file)) return true
|
|
||||||
return process.platform == "win32" ?
|
|
||||||
exec(`rd /s /q "${file.replace(/\//g, "\\")}"`) :
|
|
||||||
exec(`rm -rf "${file}"`)
|
|
||||||
} catch (err) {
|
|
||||||
console.error("删除", file, "错误", err)
|
|
||||||
return false
|
|
||||||
}}
|
|
||||||
|
|
||||||
function mv(file, target) { try {
|
|
||||||
if (!fs.existsSync(file)) return false
|
|
||||||
if (fs.existsSync(target)) rm(target)
|
|
||||||
return fs.renameSync(file, target)
|
|
||||||
} catch (err) {
|
|
||||||
console.error("移动", file, target, "错误", err)
|
|
||||||
return false
|
|
||||||
}}
|
|
||||||
|
|
||||||
function readYaml(file) { try {
|
|
||||||
if (!fs.existsSync(file)) return {}
|
|
||||||
return YAML.parse(fs.readFileSync(file, "utf-8"))
|
|
||||||
} catch (err) {
|
|
||||||
console.error("读取", file, "错误", err)
|
|
||||||
return {}
|
|
||||||
}}
|
|
||||||
|
|
||||||
function writeYaml(file, data) { try {
|
|
||||||
return fs.writeFileSync(file, YAML.stringify(data), "utf-8")
|
|
||||||
} catch (err) {
|
|
||||||
console.error("写入", file, "错误", err)
|
|
||||||
return false
|
|
||||||
}}
|
|
||||||
|
|
||||||
const bot = readYaml("config/config/bot.yaml")
|
|
||||||
const qq = readYaml("config/config/qq.yaml")
|
|
||||||
|
|
||||||
exec("git remote add trss https://gitee.com/TimeRainStarSky/Yunzai")
|
|
||||||
exec("git fetch trss main")
|
|
||||||
exec("git clean -df")
|
|
||||||
mv("config/config", "config/config_miao")
|
|
||||||
exec("git reset --hard")
|
|
||||||
exec("git checkout --track trss/main")
|
|
||||||
rm("plugins/ICQQ-Plugin")
|
|
||||||
exec("git clone --depth 1 --single-branch https://gitee.com/TimeRainStarSky/Yunzai-ICQQ-Plugin plugins/ICQQ-Plugin")
|
|
||||||
if (qq.qq) writeYaml("config/ICQQ.yaml", { bot, token: [`${qq.qq}:${qq.pwd}:${qq.platform}`] })
|
|
||||||
rm("plugins/genshin")
|
|
||||||
exec("git clone --depth 1 --single-branch https://gitee.com/TimeRainStarSky/Yunzai-genshin plugins/genshin")
|
|
||||||
exec("pnpm install --force")
|
|
||||||
|
|
||||||
console.log("迁移完成,请查看教程 启动协议端\nhttps://gitee.com/TimeRainStarSky/Yunzai\n输入 node miao 回 Miao-Yunzai")
|
|
||||||
fs.writeFileSync("miao.js", `console.log("正迁移到 Miao-Yunzai")
|
|
||||||
|
|
||||||
import fs from "node:fs"
|
|
||||||
import { execSync } from "child_process"
|
|
||||||
|
|
||||||
function exec(cmd) { try {
|
|
||||||
console.log(\`执行命令 [\${cmd}]\`)
|
|
||||||
console.log(execSync(cmd).toString())
|
|
||||||
return true
|
|
||||||
} catch (err) {
|
|
||||||
console.error("执行", cmd, "失败", err)
|
|
||||||
return false
|
|
||||||
}}
|
|
||||||
|
|
||||||
function rm(file) { try {
|
|
||||||
if (!fs.existsSync(file)) return true
|
|
||||||
return process.platform == "win32" ?
|
|
||||||
exec(\`rd /s /q "\${file.replace(/\\//g, "\\\\")}"\`) :
|
|
||||||
exec(\`rm -rf "\${file}"\`)
|
|
||||||
} catch (err) {
|
|
||||||
console.error("删除", file, "错误", err)
|
|
||||||
return false
|
|
||||||
}}
|
|
||||||
|
|
||||||
function mv(file, target) { try {
|
|
||||||
if (!fs.existsSync(file)) return false
|
|
||||||
if (fs.existsSync(target)) rm(target)
|
|
||||||
return fs.renameSync(file, target)
|
|
||||||
} catch (err) {
|
|
||||||
console.error("移动", file, target, "错误", err)
|
|
||||||
return false
|
|
||||||
}}
|
|
||||||
|
|
||||||
mv("config/config_miao", "config/config")
|
|
||||||
exec("git reset --hard")
|
|
||||||
exec("git clean -df")
|
|
||||||
rm("plugins/ICQQ-Plugin")
|
|
||||||
rm("plugins/genshin")
|
|
||||||
exec("git checkout master")
|
|
||||||
exec("git branch -D main")
|
|
||||||
exec("pnpm install --force")
|
|
||||||
|
|
||||||
console.log("迁移完成")`, "utf-8")
|
|
Loading…
Reference in New Issue