diff --git a/.env.example b/.env.example index 4f693d43..9a5c421a 100644 --- a/.env.example +++ b/.env.example @@ -1,14 +1,12 @@ -UPDATE_PORT=5300 -PUBLIC_PORT=5400 -CRON_PORT=5500 +GRPC_PORT=5500 BACK_PORT=5600 PORT=5700 -LOG_LEVEL='debug' +LOG_LEVEL='info' -SECRET='whyour' +JWT_SECRET= +JWT_EXPIRES_IN= -QINIU_AK='' -QINIU_SK='' -QINIU_SCOPE='' -TEMP='' +QINIU_AK= +QINIU_SK= +QINIU_SCOPE= diff --git a/.umirc.ts b/.umirc.ts index 48e59544..a0e057f1 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -16,16 +16,6 @@ export default defineConfig({ favicons: [`https://qn.whyour.cn/favicon.svg`], publicPath: process.env.NODE_ENV === 'production' ? './' : '/', proxy: { - [`${baseUrl}api/update`]: { - target: 'http://127.0.0.1:5300/', - changeOrigin: true, - pathRewrite: { [`^${baseUrl}api/update`]: '/api' }, - }, - [`${baseUrl}api/public`]: { - target: 'http://127.0.0.1:5400/', - changeOrigin: true, - pathRewrite: { [`^${baseUrl}api/public`]: '/api' }, - }, [`${baseUrl}api`]: { target: 'http://127.0.0.1:5600/', changeOrigin: true, diff --git a/back.d.ts b/back.d.ts deleted file mode 100644 index 8a89e1f6..00000000 --- a/back.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import 'express'; - -declare global { - namespace Express { - interface Request { - platform: string; - } - } -} diff --git a/back/api/health.ts b/back/api/health.ts new file mode 100644 index 00000000..bb961fa1 --- /dev/null +++ b/back/api/health.ts @@ -0,0 +1,27 @@ +import { Router } from 'express'; +import Logger from '../loaders/logger'; +import { HealthService } from '../services/health'; +import Container from 'typedi'; +const route = Router(); + +export default (app: Router) => { + app.use('/', route); + + route.get('/health', async (req, res) => { + try { + const healthService = Container.get(HealthService); + const health = await healthService.check(); + res.status(200).send({ + code: 200, + data: health, + }); + } catch (err: any) { + Logger.error('Health check failed:', err); + res.status(500).send({ + code: 500, + message: 'Health check failed', + error: err.message, + }); + } + }); +}; diff --git a/back/api/index.ts b/back/api/index.ts index 36c56599..6dcab62f 100644 --- a/back/api/index.ts +++ b/back/api/index.ts @@ -9,6 +9,8 @@ import open from './open'; import dependence from './dependence'; import system from './system'; import subscription from './subscription'; +import update from './update'; +import health from './health'; export default () => { const app = Router(); @@ -22,6 +24,8 @@ export default () => { dependence(app); system(app); subscription(app); + update(app); + health(app); return app; }; diff --git a/back/api/update.ts b/back/api/update.ts new file mode 100644 index 00000000..5d50d8c6 --- /dev/null +++ b/back/api/update.ts @@ -0,0 +1,51 @@ +import { NextFunction, Request, Response, Router } from 'express'; +import Container from 'typedi'; +import Logger from '../loaders/logger'; +import SystemService from '../services/system'; +const route = Router(); + +export default (app: Router) => { + app.use('/update', route); + + route.put( + '/reload', + async (req: Request, res: Response, next: NextFunction) => { + try { + const systemService = Container.get(SystemService); + const result = await systemService.reloadSystem(); + res.send(result); + } catch (e) { + Logger.error('🔥 error: %o', e); + return next(e); + } + }, + ); + + route.put( + '/system', + async (req: Request, res: Response, next: NextFunction) => { + try { + const systemService = Container.get(SystemService); + const result = await systemService.reloadSystem('system'); + res.send(result); + } catch (e) { + Logger.error('🔥 error: %o', e); + return next(e); + } + }, + ); + + route.put( + '/data', + async (req: Request, res: Response, next: NextFunction) => { + try { + const systemService = Container.get(SystemService); + const result = await systemService.reloadSystem('data'); + res.send(result); + } catch (e) { + Logger.error('🔥 error: %o', e); + return next(e); + } + }, + ); +}; diff --git a/back/app.ts b/back/app.ts index ff25583a..5b726667 100644 --- a/back/app.ts +++ b/back/app.ts @@ -1,30 +1,92 @@ -import 'reflect-metadata'; // We need this in order to use @Decorators -import config from './config'; +import 'reflect-metadata'; +import compression from 'compression'; +import cors from 'cors'; import express from 'express'; +import helmet from 'helmet'; +import { Container } from 'typedi'; +import config from './config'; import Logger from './loaders/logger'; +import { monitoringMiddleware } from './middlewares/monitoring'; +import { GrpcServerService } from './services/grpc'; +import { HttpServerService } from './services/http'; +import { metricsService } from './services/metrics'; -async function startServer() { - const app = express(); +class Application { + private app: express.Application; + private server: any; + private httpServerService: HttpServerService; + private grpcServerService: GrpcServerService; + private isShuttingDown = false; - await require('./loaders/db').default(); + constructor() { + this.app = express(); + this.httpServerService = Container.get(HttpServerService); + this.grpcServerService = Container.get(GrpcServerService); + } - await require('./loaders/initFile').default(); + async start() { + try { + await this.initializeDatabase(); + this.setupMiddlewares(); + await this.initializeServices(); + this.setupGracefulShutdown(); - await require('./loaders/app').default({ expressApp: app }); - - const server = app - .listen(config.port, '0.0.0.0', () => { - Logger.debug(`✌️ 后端服务启动成功!`); - console.debug(`✌️ 后端服务启动成功!`); process.send?.('ready'); - }) - .on('error', (err) => { - Logger.error(err); - console.error(err); + } catch (error) { + Logger.error('Failed to start application:', error); process.exit(1); - }); + } + } - await require('./loaders/server').default({ server }); + private async initializeDatabase() { + await require('./loaders/db').default(); + } + + private setupMiddlewares() { + this.app.use(helmet()); + this.app.use(cors(config.cors)); + this.app.use(compression()); + this.app.use(monitoringMiddleware); + } + + private async initializeServices() { + await this.grpcServerService.initialize(); + + await require('./loaders/app').default({ app: this.app }); + + this.server = await this.httpServerService.initialize( + this.app, + config.port, + ); + + await require('./loaders/server').default({ server: this.server }); + } + + private setupGracefulShutdown() { + const shutdown = async () => { + if (this.isShuttingDown) return; + this.isShuttingDown = true; + + Logger.info('Shutting down services...'); + try { + await Promise.all([ + this.grpcServerService.shutdown(), + this.httpServerService.shutdown(), + ]); + process.exit(0); + } catch (error) { + Logger.error('Error during shutdown:', error); + process.exit(1); + } + }; + + process.on('SIGTERM', shutdown); + process.on('SIGINT', shutdown); + } } -startServer(); +const app = new Application(); +app.start().catch((error) => { + Logger.error('Application failed to start:', error); + process.exit(1); +}); diff --git a/back/config/index.ts b/back/config/index.ts index 9b39daf4..40bde347 100644 --- a/back/config/index.ts +++ b/back/config/index.ts @@ -2,12 +2,60 @@ import dotenv from 'dotenv'; import path from 'path'; import { createRandomString } from './share'; +dotenv.config({ + path: path.join(__dirname, '../../.env'), +}); + +interface Config { + port: number; + grpcPort: number; + nodeEnv: string; + isDevelopment: boolean; + isProduction: boolean; + jwt: { + secret: string; + expiresIn?: string; + }; + cors: { + origin: string[]; + methods: string[]; + }; + logs: { + level: string; + }; + api: { + prefix: string; + }; +} + +const config: Config = { + port: parseInt(process.env.BACK_PORT || '5600', 10), + grpcPort: parseInt(process.env.GRPC_PORT || '5500', 10), + nodeEnv: process.env.NODE_ENV || 'development', + isDevelopment: process.env.NODE_ENV === 'development', + isProduction: process.env.NODE_ENV === 'production', + logs: { + level: process.env.LOG_LEVEL || 'silly', + }, + api: { + prefix: '/api', + }, + jwt: { + secret: process.env.JWT_SECRET || createRandomString(16, 32), + expiresIn: process.env.JWT_EXPIRES_IN, + }, + cors: { + origin: process.env.CORS_ORIGIN + ? process.env.CORS_ORIGIN.split(',') + : ['*'], + methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], + }, +}; + process.env.NODE_ENV = process.env.NODE_ENV || 'development'; if (!process.env.QL_DIR) { - // 声明QL_DIR环境变量 let qlHomePath = path.join(__dirname, '../../'); - // 生产环境 if (qlHomePath.endsWith('/static/')) { qlHomePath = path.join(qlHomePath, '../'); } @@ -65,17 +113,8 @@ if (envFound.error) { } export default { - port: parseInt(process.env.BACK_PORT as string, 10), - cronPort: parseInt(process.env.CRON_PORT as string, 10), - publicPort: parseInt(process.env.PUBLIC_PORT as string, 10), - updatePort: parseInt(process.env.UPDATE_PORT as string, 10), - secret: process.env.SECRET || createRandomString(16, 32), - logs: { - level: process.env.LOG_LEVEL || 'silly', - }, - api: { - prefix: '/api', - }, + ...config, + jwt: config.jwt, rootPath, tmpPath, dataPath, @@ -118,6 +157,7 @@ export default { bakPath, apiWhiteList: [ '/api/user/login', + '/api/health', '/open/auth/token', '/api/user/two-factor/login', '/api/system', diff --git a/back/config/util.ts b/back/config/util.ts index 3253b741..2731307e 100644 --- a/back/config/util.ts +++ b/back/config/util.ts @@ -4,7 +4,7 @@ import got from 'got'; import iconv from 'iconv-lite'; import { exec } from 'child_process'; import FormData from 'form-data'; -import psTreeFun from 'pstree.remy'; +import psTreeFun from 'ps-tree'; import { promisify } from 'util'; import { load } from 'js-yaml'; import config from './index'; @@ -462,11 +462,11 @@ export function parseBody( export function psTree(pid: number): Promise { return new Promise((resolve, reject) => { - psTreeFun(pid, (err: any, pids: number[]) => { + psTreeFun(pid, (err: any, children) => { if (err) { reject(err); } - resolve(pids.filter((x) => !isNaN(x))); + resolve(children.map((x) => Number(x.PID)).filter((x) => !isNaN(x))); }); }); } diff --git a/back/index.d.ts b/back/index.d.ts deleted file mode 100644 index 4301a545..00000000 --- a/back/index.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -declare namespace Express { - interface Request { - platform: 'desktop' | 'mobile'; - } -} - -declare module 'pstree.remy'; diff --git a/back/loaders/app.ts b/back/loaders/app.ts index 37e43dfe..157c3c1d 100644 --- a/back/loaders/app.ts +++ b/back/loaders/app.ts @@ -5,25 +5,24 @@ import initData from './initData'; import { Application } from 'express'; import linkDeps from './deps'; import initTask from './initTask'; +import initFile from './initFile'; -export default async ({ expressApp }: { expressApp: Application }) => { +export default async ({ app }: { app: Application }) => { depInjectorLoader(); Logger.info('✌️ Dependency loaded'); - console.log('✌️ Dependency loaded'); - - await initData(); - Logger.info('✌️ Init data loaded'); - console.log('✌️ Init data loaded'); await linkDeps(); Logger.info('✌️ Link deps loaded'); - console.log('✌️ Link deps loaded'); + + initFile(); + Logger.info('✌️ Init file loaded'); + + await initData(); + Logger.info('✌️ Init data loaded'); initTask(); Logger.info('✌️ Init task loaded'); - console.log('✌️ Init task loaded'); - expressLoader({ app: expressApp }); + expressLoader({ app }); Logger.info('✌️ Express loaded'); - console.log('✌️ Express loaded'); }; diff --git a/back/loaders/db.ts b/back/loaders/db.ts index a2d7fb76..ac142a2d 100644 --- a/back/loaders/db.ts +++ b/back/loaders/db.ts @@ -57,10 +57,8 @@ export default async () => { await sequelize.query('alter table Crontabs add column task_after TEXT'); } catch (error) {} - console.log('✌️ DB loaded'); Logger.info('✌️ DB loaded'); } catch (error) { - console.error('✌️ DB load failed'); - Logger.error(error); + Logger.error('✌️ DB load failed', error); } }; diff --git a/back/loaders/express.ts b/back/loaders/express.ts index fe17e84c..aa3d0ef6 100644 --- a/back/loaders/express.ts +++ b/back/loaders/express.ts @@ -7,9 +7,7 @@ import { UnauthorizedError, expressjwt } from 'express-jwt'; import { getPlatform, getToken } from '../config/util'; import rewrite from 'express-urlrewrite'; import { errors } from 'celebrate'; -import { createProxyMiddleware } from 'http-proxy-middleware'; import { serveEnv } from '../config/serverEnv'; -import Logger from './logger'; import { IKeyvStore, shareStore } from '../shared/store'; export default ({ app }: { app: Application }) => { @@ -18,22 +16,12 @@ export default ({ app }: { app: Application }) => { app.get(`${config.api.prefix}/env.js`, serveEnv); app.use(`${config.api.prefix}/static`, express.static(config.uploadPath)); - app.use( - '/api/public', - createProxyMiddleware({ - target: `http://0.0.0.0:${config.publicPort}/api`, - changeOrigin: true, - pathRewrite: { '/api/public': '' }, - logger: Logger, - }), - ); - app.use(bodyParser.json({ limit: '50mb' })); app.use(bodyParser.urlencoded({ limit: '50mb', extended: true })); app.use( expressjwt({ - secret: config.secret, + secret: config.jwt.secret, algorithms: ['HS384'], }).unless({ path: [...config.apiWhiteList, /^\/open\//], @@ -50,7 +38,7 @@ export default ({ app }: { app: Application }) => { return next(); }); - app.use(async (req, res, next) => { + app.use(async (req: Request, res, next) => { const headerToken = getToken(req); if (req.path.startsWith('/open/')) { const apps = await shareStore.getApps(); diff --git a/back/loaders/initFile.ts b/back/loaders/initFile.ts index d613085e..6013510b 100644 --- a/back/loaders/initFile.ts +++ b/back/loaders/initFile.ts @@ -122,5 +122,4 @@ export default async () => { } Logger.info('✌️ Init file down'); - console.log('✌️ Init file down'); }; diff --git a/back/loaders/logger.ts b/back/loaders/logger.ts index 94b4d460..99f1d391 100644 --- a/back/loaders/logger.ts +++ b/back/loaders/logger.ts @@ -4,35 +4,60 @@ import config from '../config'; import path from 'path'; const levelMap: Record = { - info: '\ue6f5', - warn: '\ue880', - error: '\ue602', - debug: '\ue67f' -} - -const customFormat = winston.format.combine( - winston.format.splat(), - winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), - winston.format.align(), - winston.format.printf((i) => `[${levelMap[i.level]}${i.level}] [${[i.timestamp]}]: ${i.message}`), -); - -const defaultOptions = { - format: customFormat, - datePattern: "YYYY-MM-DD", - maxSize: "20m", - maxFiles: "7d", + info: 'ℹ️', // info图标 + warn: '⚠️', // 警告图标 + error: '❌', // 错误图标 + debug: '🐛', // debug调试图标 }; +const baseFormat = [ + winston.format.splat(), + winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), + winston.format.align(), +]; + +const consoleFormat = winston.format.combine( + winston.format.colorize({ level: true }), + ...baseFormat, + winston.format.printf((info) => { + return `[${info.level} ${info.timestamp}]:${info.message}`; + }), +); + +const plainFormat = winston.format.combine( + winston.format.uncolorize(), + ...baseFormat, + winston.format.printf((info) => { + return `[${levelMap[info.level] || ''}${info.level} ${info.timestamp}]:${ + info.message + }`; + }), +); + +const consoleTransport = new winston.transports.Console({ + format: consoleFormat, + level: 'debug', +}); + +const fileTransport = new winston.transports.DailyRotateFile({ + filename: path.join(config.systemLogPath, '%DATE%.log'), + datePattern: 'YYYY-MM-DD', + maxSize: '20m', + maxFiles: '7d', + format: plainFormat, + level: config.logs.level || 'info', +}); + const LoggerInstance = winston.createLogger({ - level: config.logs.level, + level: 'debug', levels: winston.config.npm.levels, - transports: [ - new winston.transports.DailyRotateFile({ - filename: path.join(config.systemLogPath, '%DATE%.log'), - ...defaultOptions, - }) - ], + transports: [consoleTransport, fileTransport], + exceptionHandlers: [consoleTransport, fileTransport], + rejectionHandlers: [consoleTransport, fileTransport], +}); + +LoggerInstance.on('error', (error) => { + console.error('Logger error:', error); }); export default LoggerInstance; diff --git a/back/loaders/update.ts b/back/loaders/update.ts deleted file mode 100644 index e078fe7f..00000000 --- a/back/loaders/update.ts +++ /dev/null @@ -1,106 +0,0 @@ -import bodyParser from 'body-parser'; -import { errors } from 'celebrate'; -import cors from 'cors'; -import { Application, NextFunction, Request, Response } from 'express'; -import { expressjwt } from 'express-jwt'; -import Container from 'typedi'; -import config from '../config'; -import SystemService from '../services/system'; -import Logger from './logger'; - -export default ({ app }: { app: Application }) => { - app.set('trust proxy', 'loopback'); - app.use(cors()); - - app.use(bodyParser.json({ limit: '50mb' })); - app.use(bodyParser.urlencoded({ limit: '50mb', extended: true })); - - app.use( - expressjwt({ - secret: config.secret, - algorithms: ['HS384'], - }), - ); - - app.put( - '/api/reload', - async (req: Request, res: Response, next: NextFunction) => { - try { - const systemService = Container.get(SystemService); - const result = await systemService.reloadSystem(); - res.send(result); - } catch (e) { - Logger.error('🔥 error: %o', e); - return next(e); - } - }, - ); - - app.put( - '/api/system', - async (req: Request, res: Response, next: NextFunction) => { - try { - const systemService = Container.get(SystemService); - const result = await systemService.reloadSystem('system'); - res.send(result); - } catch (e) { - Logger.error('🔥 error: %o', e); - return next(e); - } - }, - ); - - app.put( - '/api/data', - async (req: Request, res: Response, next: NextFunction) => { - try { - const systemService = Container.get(SystemService); - const result = await systemService.reloadSystem('data'); - res.send(result); - } catch (e) { - Logger.error('🔥 error: %o', e); - return next(e); - } - }, - ); - - app.use((req, res, next) => { - const err: any = new Error('Not Found'); - err['status'] = 404; - next(err); - }); - - app.use(errors()); - - app.use( - ( - err: Error & { status: number }, - req: Request, - res: Response, - next: NextFunction, - ) => { - if (err.name === 'UnauthorizedError') { - return res - .status(err.status) - .send({ code: 401, message: err.message }) - .end(); - } - return next(err); - }, - ); - - app.use( - ( - err: Error & { status: number }, - req: Request, - res: Response, - next: NextFunction, - ) => { - res.status(err.status || 500); - res.json({ - code: err.status || 500, - message: err.message, - }); - }, - ); -}; diff --git a/back/middlewares/monitoring.ts b/back/middlewares/monitoring.ts new file mode 100644 index 00000000..d0d3f2f4 --- /dev/null +++ b/back/middlewares/monitoring.ts @@ -0,0 +1,80 @@ +import { Request, Response, NextFunction } from 'express'; +import Logger from '../loaders/logger'; +import { performance } from 'perf_hooks'; +import { metricsService } from '../services/metrics'; + +interface RequestMetrics { + method: string; + path: string; + duration: number; + statusCode: number; + timestamp: number; + platform?: string; +} + +const requestMetrics: RequestMetrics[] = []; + +export const monitoringMiddleware = ( + req: Request, + res: Response, + next: NextFunction, +) => { + const start = performance.now(); + const originalEnd = res.end; + + res.end = function (chunk?: any, encoding?: any, cb?: any) { + const duration = performance.now() - start; + const metric: RequestMetrics = { + method: req.method, + path: req.path, + duration, + statusCode: res.statusCode, + timestamp: Date.now(), + platform: req.platform, + }; + + requestMetrics.push(metric); + metricsService.record('http_request', duration, { + method: req.method, + path: req.path, + statusCode: res.statusCode.toString(), + ...(req.platform && { platform: req.platform }), + }); + + if (requestMetrics.length > 1000) { + requestMetrics.shift(); + } + + if (duration > 1000) { + Logger.warn( + `Slow request detected: ${req.method} ${ + req.path + } took ${duration.toFixed(2)}ms`, + ); + } + + return originalEnd.call(this, chunk, encoding, cb); + }; + + next(); +}; + +export const getMetrics = () => { + return { + totalRequests: requestMetrics.length, + averageDuration: + requestMetrics.reduce((acc, curr) => acc + curr.duration, 0) / + requestMetrics.length, + requestsByMethod: requestMetrics.reduce((acc, curr) => { + acc[curr.method] = (acc[curr.method] || 0) + 1; + return acc; + }, {} as Record), + requestsByPlatform: requestMetrics.reduce((acc, curr) => { + if (curr.platform) { + acc[curr.platform] = (acc[curr.platform] || 0) + 1; + } + return acc; + }, {} as Record), + recentRequests: requestMetrics.slice(-10), + }; +}; diff --git a/back/public.ts b/back/public.ts deleted file mode 100644 index 47527545..00000000 --- a/back/public.ts +++ /dev/null @@ -1,35 +0,0 @@ -import express from 'express'; -import Logger from './loaders/logger'; -import config from './config'; -import { HealthClient } from './protos/health'; -import { credentials } from '@grpc/grpc-js'; - -const app = express(); -const client = new HealthClient( - `0.0.0.0:${config.cronPort}`, - credentials.createInsecure(), - { 'grpc.enable_http_proxy': 0 }, -); - -app.get('/api/health', (req, res) => { - client.check({ service: 'cron' }, (err, response) => { - if (err) { - return res.status(200).send({ code: 500, error: err }); - } - return res.status(200).send({ code: 200, data: response }); - }); -}); - -app - .listen(config.publicPort, '0.0.0.0', async () => { - await require('./loaders/db').default(); - - Logger.debug(`✌️ 公共服务启动成功!`); - console.debug(`✌️ 公共服务启动成功!`); - process.send?.('ready'); - }) - .on('error', (err) => { - Logger.error(err); - console.error(err); - process.exit(1); - }); diff --git a/back/schedule/client.ts b/back/schedule/client.ts index 183841c2..99bf364a 100644 --- a/back/schedule/client.ts +++ b/back/schedule/client.ts @@ -10,7 +10,7 @@ import config from '../config'; class Client { private client = new CronClient( - `0.0.0.0:${config.cronPort}`, + `0.0.0.0:${config.grpcPort}`, credentials.createInsecure(), { 'grpc.enable_http_proxy': 0 }, ); diff --git a/back/schedule/index.ts b/back/schedule/index.ts deleted file mode 100644 index 1674b6a4..00000000 --- a/back/schedule/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Server, ServerCredentials } from '@grpc/grpc-js'; -import { CronService } from '../protos/cron'; -import { addCron } from './addCron'; -import { delCron } from './delCron'; -import { HealthService } from '../protos/health'; -import { check } from './health'; -import config from '../config'; -import Logger from '../loaders/logger'; -import { ApiService } from '../protos/api'; -import * as Api from './api'; - -const server = new Server({ 'grpc.enable_http_proxy': 0 }); -server.addService(HealthService, { check }); -server.addService(CronService, { addCron, delCron }); -server.addService(ApiService, Api); -server.bindAsync( - `0.0.0.0:${config.cronPort}`, - ServerCredentials.createInsecure(), - (err, port) => { - if (err) { - throw err; - } - Logger.debug(`✌️ 定时服务启动成功!`); - console.debug(`✌️ 定时服务启动成功!`); - process.send?.('ready'); - }, -); diff --git a/back/services/grpc.ts b/back/services/grpc.ts new file mode 100644 index 00000000..e8ea2282 --- /dev/null +++ b/back/services/grpc.ts @@ -0,0 +1,64 @@ +import { Server, ServerCredentials } from '@grpc/grpc-js'; +import { CronService } from '../protos/cron'; +import { HealthService } from '../protos/health'; +import { ApiService } from '../protos/api'; +import { addCron } from '../schedule/addCron'; +import { delCron } from '../schedule/delCron'; +import { check } from '../schedule/health'; +import * as Api from '../schedule/api'; +import Logger from '../loaders/logger'; +import { promisify } from 'util'; +import config from '../config'; +import { metricsService } from './metrics'; +import { Service } from 'typedi'; + +@Service() +export class GrpcServerService { + private server: Server = new Server({ 'grpc.enable_http_proxy': 0 }); + + async initialize() { + try { + this.server.addService(HealthService, { check }); + this.server.addService(CronService, { addCron, delCron }); + this.server.addService(ApiService, Api); + + const grpcPort = config.grpcPort; + const bindAsync = promisify(this.server.bindAsync).bind(this.server); + await bindAsync( + `0.0.0.0:${grpcPort}`, + ServerCredentials.createInsecure(), + ); + Logger.debug(`✌️ gRPC service started successfully`); + + metricsService.record('grpc_service_start', 1, { + port: grpcPort.toString(), + }); + + return grpcPort; + } catch (err) { + Logger.error('Failed to start gRPC service:', err); + throw err; + } + } + + async shutdown() { + try { + if (this.server) { + await new Promise((resolve) => { + this.server.tryShutdown(() => { + Logger.debug('gRPC service stopped'); + metricsService.record('grpc_service_stop', 1); + resolve(null); + }); + }); + } + } catch (err) { + Logger.error('Error while shutting down gRPC service:', err); + throw err; + } + } + + getServer() { + return this.server; + } +} diff --git a/back/services/health.ts b/back/services/health.ts new file mode 100644 index 00000000..d971768d --- /dev/null +++ b/back/services/health.ts @@ -0,0 +1,72 @@ +import { Service } from 'typedi'; +import Logger from '../loaders/logger'; +import { GrpcServerService } from './grpc'; +import { HttpServerService } from './http'; + +interface HealthStatus { + status: 'ok' | 'error'; + services: { + http: boolean; + grpc: boolean; + }; + metrics: { + uptime: number; + memory: { + used: number; + total: number; + }; + }; +} + +@Service() +export class HealthService { + private startTime = Date.now(); + + constructor( + private grpcServerService: GrpcServerService, + private httpServerService: HttpServerService, + ) {} + + async check(): Promise { + const status: HealthStatus = { + status: 'ok', + services: { + http: true, + grpc: true, + }, + metrics: { + uptime: Math.floor((Date.now() - this.startTime) / 1000), + memory: { + used: process.memoryUsage().heapUsed, + total: process.memoryUsage().heapTotal, + }, + }, + }; + + try { + const httpServer = this.httpServerService.getServer(); + if (!httpServer) { + status.services.http = false; + status.status = 'error'; + } + } catch (err) { + status.services.http = false; + status.status = 'error'; + Logger.error('HTTP server check failed:', err); + } + + try { + const grpcServer = this.grpcServerService.getServer(); + if (!grpcServer) { + status.services.grpc = false; + status.status = 'error'; + } + } catch (err) { + status.services.grpc = false; + status.status = 'error'; + Logger.error('gRPC server check failed:', err); + } + + return status; + } +} diff --git a/back/services/http.ts b/back/services/http.ts new file mode 100644 index 00000000..c21f5e07 --- /dev/null +++ b/back/services/http.ts @@ -0,0 +1,53 @@ +import express from 'express'; +import Logger from '../loaders/logger'; +import { metricsService } from './metrics'; +import { Service } from 'typedi'; +import { Server } from 'http'; + +@Service() +export class HttpServerService { + private server?: Server = undefined; + + async initialize(expressApp: express.Application, port: number) { + try { + return new Promise((resolve, reject) => { + this.server = expressApp.listen(port, '0.0.0.0', () => { + Logger.debug(`✌️ HTTP service started successfully`); + metricsService.record('http_service_start', 1, { + port: port.toString(), + }); + resolve(this.server); + }); + + this.server.on('error', (err: Error) => { + Logger.error('Failed to start HTTP service:', err); + reject(err); + }); + }); + } catch (err) { + Logger.error('Failed to start HTTP service:', err); + throw err; + } + } + + async shutdown() { + try { + if (this.server) { + await new Promise((resolve) => { + this.server?.close(() => { + Logger.debug('HTTP service stopped'); + metricsService.record('http_service_stop', 1); + resolve(null); + }); + }); + } + } catch (err) { + Logger.error('Error while shutting down HTTP service:', err); + throw err; + } + } + + getServer() { + return this.server; + } +} diff --git a/back/services/metrics.ts b/back/services/metrics.ts new file mode 100644 index 00000000..7ed44664 --- /dev/null +++ b/back/services/metrics.ts @@ -0,0 +1,92 @@ +import { performance } from 'perf_hooks'; +import Logger from '../loaders/logger'; + +interface Metric { + name: string; + value: number; + timestamp: number; + tags?: Record; +} + +class MetricsService { + private metrics: Metric[] = []; + private static instance: MetricsService; + + private constructor() { + // 定期清理旧数据 + setInterval(() => { + const oneHourAgo = Date.now() - 3600000; + this.metrics = this.metrics.filter(m => m.timestamp > oneHourAgo); + }, 60000); + } + + static getInstance(): MetricsService { + if (!MetricsService.instance) { + MetricsService.instance = new MetricsService(); + } + return MetricsService.instance; + } + + record(name: string, value: number, tags?: Record) { + this.metrics.push({ + name, + value, + timestamp: Date.now(), + tags, + }); + } + + measure(name: string, fn: () => void, tags?: Record) { + const start = performance.now(); + try { + fn(); + } finally { + const duration = performance.now() - start; + this.record(name, duration, tags); + } + } + + async measureAsync(name: string, fn: () => Promise, tags?: Record) { + const start = performance.now(); + try { + await fn(); + } finally { + const duration = performance.now() - start; + this.record(name, duration, tags); + } + } + + getMetrics(name?: string, tags?: Record) { + let filtered = this.metrics; + + if (name) { + filtered = filtered.filter(m => m.name === name); + } + + if (tags) { + filtered = filtered.filter(m => { + if (!m.tags) return false; + return Object.entries(tags).every(([key, value]) => m.tags![key] === value); + }); + } + + return { + count: filtered.length, + average: filtered.reduce((acc, curr) => acc + curr.value, 0) / filtered.length, + min: Math.min(...filtered.map(m => m.value)), + max: Math.max(...filtered.map(m => m.value)), + metrics: filtered, + }; + } + + report() { + const report = { + timestamp: Date.now(), + metrics: this.getMetrics(), + }; + Logger.info('性能指标报告:', report); + return report; + } +} + +export const metricsService = MetricsService.getInstance(); \ No newline at end of file diff --git a/back/services/system.ts b/back/services/system.ts index 80be9afd..85f961fe 100644 --- a/back/services/system.ts +++ b/back/services/system.ts @@ -357,8 +357,15 @@ export default class SystemService { public async reloadSystem(target?: 'system' | 'data') { const cmd = `real_time=true ql reload ${target || ''}`; - const cp = spawn(cmd, { shell: '/bin/bash' }); + const cp = spawn(cmd, { + shell: '/bin/bash', + detached: true, + stdio: 'ignore', + }); cp.unref(); + setTimeout(() => { + process.exit(0); + }); return { code: 200 }; } diff --git a/back/services/user.ts b/back/services/user.ts index a2cb0ef7..5f552390 100644 --- a/back/services/user.ts +++ b/back/services/user.ts @@ -93,9 +93,9 @@ export default class UserService { } if (username === cUsername && password === cPassword) { const data = createRandomString(50, 100); - const expiration = twoFactorActivated ? 60 : 20; - let token = jwt.sign({ data }, config.secret as any, { - expiresIn: 60 * 60 * 24 * expiration, + const expiration = twoFactorActivated ? '60d' : '20d'; + let token = jwt.sign({ data }, config.jwt.secret, { + expiresIn: config.jwt.expiresIn || expiration, algorithm: 'HS384', }); @@ -131,7 +131,14 @@ export default class UserService { this.getLoginLog(); return { code: 200, - data: { token, lastip, lastaddr, lastlogon, retries, platform }, + data: { + token, + lastip, + lastaddr, + lastlogon, + retries, + platform, + }, }; } else { await this.updateAuthInfo(content, { diff --git a/back/shared/pLimit.ts b/back/shared/pLimit.ts index 225918b8..f84763ad 100644 --- a/back/shared/pLimit.ts +++ b/back/shared/pLimit.ts @@ -37,7 +37,7 @@ class TaskLimit { concurrency: Math.max(os.cpus().length, 4), }); private client = new ApiClient( - `0.0.0.0:${config.cronPort}`, + `0.0.0.0:${config.grpcPort}`, credentials.createInsecure(), { 'grpc.enable_http_proxy': 0 }, ); diff --git a/back/token.ts b/back/token.ts index 6aeed6a4..d307c623 100755 --- a/back/token.ts +++ b/back/token.ts @@ -2,7 +2,6 @@ import 'reflect-metadata'; import OpenService from './services/open'; import { Container } from 'typedi'; import LoggerInstance from './loaders/logger'; -import fs from 'fs'; import config from './config'; import path from 'path'; import os from 'os'; diff --git a/tsconfig.back.json b/back/tsconfig.json similarity index 67% rename from tsconfig.back.json rename to back/tsconfig.json index 12c22445..d431941c 100644 --- a/tsconfig.back.json +++ b/back/tsconfig.json @@ -2,7 +2,11 @@ "compilerOptions": { "target": "es2017", "lib": ["ESNext"], - "typeRoots": ["./node_modules/celebrate/lib", "./node_modules/@types"], + "typeRoots": [ + "./types", + "../node_modules/celebrate/lib", + "../node_modules/@types" + ], "allowSyntheticDefaultImports": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, @@ -13,12 +17,11 @@ "module": "commonjs", "pretty": true, "sourceMap": true, - "outDir": "./static/build", + "outDir": "../static/build", "allowJs": true, "noEmit": false, "esModuleInterop": true }, - "include": ["./back/**/*", "./back.d.ts"], - "exclude": ["node_modules"], - "files": ["./back/index.d.ts"] + "include": ["./**/*"], + "exclude": ["node_modules"] } diff --git a/back/types/express.d.ts b/back/types/express.d.ts new file mode 100644 index 00000000..4a8fd216 --- /dev/null +++ b/back/types/express.d.ts @@ -0,0 +1,11 @@ +/// + +export {}; + +declare global { + namespace Express { + interface Request { + platform: 'desktop' | 'mobile'; + } + } +} \ No newline at end of file diff --git a/back/update.ts b/back/update.ts deleted file mode 100644 index a9d7f270..00000000 --- a/back/update.ts +++ /dev/null @@ -1,27 +0,0 @@ -import 'reflect-metadata'; // We need this in order to use @Decorators -import config from './config'; -import express from 'express'; -import depInjectorLoader from './loaders/depInjector'; -import Logger from './loaders/logger'; - - -async function startServer() { - const app = express(); - depInjectorLoader(); - - await require('./loaders/update').default({ app }); - - app - .listen(config.updatePort, '0.0.0.0', () => { - Logger.debug(`✌️ 更新服务启动成功!`); - console.debug(`✌️ 更新服务启动成功!`); - process.send?.('ready'); - }) - .on('error', (err) => { - Logger.error(err); - console.error(err); - process.exit(1); - }); -} - -startServer(); diff --git a/docker/310.Dockerfile b/docker/310.Dockerfile index 338430fb..ed108a9a 100644 --- a/docker/310.Dockerfile +++ b/docker/310.Dockerfile @@ -86,6 +86,6 @@ COPY --from=builder /tmp/build/node_modules/. /ql/node_modules/ WORKDIR ${QL_DIR} HEALTHCHECK --interval=5s --timeout=2s --retries=20 \ - CMD curl -sf --noproxy '*' http://127.0.0.1:5400/api/health || exit 1 + CMD curl -sf --noproxy '*' http://127.0.0.1:5600/api/health || exit 1 ENTRYPOINT ["./docker/docker-entrypoint.sh"] diff --git a/docker/Dockerfile b/docker/Dockerfile index 33569ea8..f735a96c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -86,6 +86,6 @@ COPY --from=builder /tmp/build/node_modules/. /ql/node_modules/ WORKDIR ${QL_DIR} HEALTHCHECK --interval=5s --timeout=2s --retries=20 \ - CMD curl -sf --noproxy '*' http://127.0.0.1:5400/api/health || exit 1 + CMD curl -sf --noproxy '*' http://127.0.0.1:5600/api/health || exit 1 ENTRYPOINT ["./docker/docker-entrypoint.sh"] diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index 6ba88f08..eb772688 100755 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -21,7 +21,6 @@ nginx -s reload 2>/dev/null || nginx -c /etc/nginx/nginx.conf echo -e "nginx启动成功...\n" echo -e "======================4. 启动pm2服务========================\n" -reload_update reload_pm2 if [[ $AutoStartBot == true ]]; then diff --git a/docker/front.conf b/docker/front.conf index ee2cb9d7..1fe4c9ff 100644 --- a/docker/front.conf +++ b/docker/front.conf @@ -2,14 +2,6 @@ upstream baseApi { server 0.0.0.0:5600; } -upstream publicApi { - server 0.0.0.0:5400; -} - -upstream updateApi { - server 0.0.0.0:5300; -} - map $http_upgrade $connection_upgrade { default keep-alive; 'websocket' upgrade; @@ -20,30 +12,6 @@ server { IPV6_CONFIG ssl_session_timeout 5m; - location QL_BASE_URLapi/update/ { - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass http://updateApi/api/; - proxy_buffering off; - proxy_redirect default; - proxy_connect_timeout 1800; - proxy_send_timeout 1800; - proxy_read_timeout 1800; - } - - location QL_BASE_URLapi/public/ { - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass http://publicApi/api/; - proxy_buffering off; - proxy_redirect default; - proxy_connect_timeout 1800; - proxy_send_timeout 1800; - proxy_read_timeout 1800; - } - location QL_BASE_URLapi/ { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; diff --git a/ecosystem.config.js b/ecosystem.config.js index 0a48440c..1d476b70 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -1,14 +1,14 @@ module.exports = { apps: [ { - name: 'schedule', - max_restarts: 10, - kill_timeout: 15000, + name: 'qinglong', + max_restarts: 5, + kill_timeout: 1000, wait_ready: true, - listen_timeout: 10000, + listen_timeout: 5000, source_map_support: true, time: true, - script: 'static/build/schedule/index.js', + script: 'static/build/app.js', env: { http_proxy: '', https_proxy: '', @@ -18,25 +18,5 @@ module.exports = { ALL_PROXY: '', }, }, - { - name: 'public', - max_restarts: 10, - kill_timeout: 15000, - wait_ready: true, - listen_timeout: 10000, - source_map_support: true, - time: true, - script: 'static/build/public.js', - }, - { - name: 'panel', - max_restarts: 10, - kill_timeout: 15000, - wait_ready: true, - listen_timeout: 10000, - source_map_support: true, - time: true, - script: 'static/build/app.js', - }, ], }; diff --git a/nodemon.json b/nodemon.json index 23ebe045..7192e994 100644 --- a/nodemon.json +++ b/nodemon.json @@ -1,5 +1,5 @@ { "watch": ["back", ".env"], "ext": "js,ts,json", - "exec": "ts-node -P tsconfig.back.json ./back/app.ts" + "exec": "ts-node -P ./back/tsconfig.json ./back/app.ts" } diff --git a/other.config.js b/other.config.js deleted file mode 100644 index d8c1852b..00000000 --- a/other.config.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - apps: [ - { - name: 'update', - max_restarts: 10, - kill_timeout: 15000, - wait_ready: true, - listen_timeout: 10000, - time: true, - script: 'static/build/update.js', - }, - ], -}; diff --git a/package.json b/package.json index e9ce468c..8cf26c16 100644 --- a/package.json +++ b/package.json @@ -2,17 +2,11 @@ "private": true, "scripts": { "start": "concurrently -n w: npm:start:*", - "start:update": "ts-node -P tsconfig.back.json ./back/update.ts", - "start:public": "ts-node -P tsconfig.back.json ./back/public.ts", - "start:rpc": "ts-node -P tsconfig.back.json ./back/schedule/index.ts", "start:back": "nodemon", "start:front": "max dev", "build:front": "max build", - "build:back": "tsc -p tsconfig.back.json", + "build:back": "tsc -p back/tsconfig.json", "panel": "npm run build:back && node static/build/app.js", - "schedule": "npm run build:back && node static/build/schedule/index.js", - "public": "npm run build:back && node static/build/public.js", - "update": "npm run build:back && node static/build/update.js", "gen:proto": "protoc --experimental_allow_proto3_optional --plugin=./node_modules/.bin/protoc-gen-ts_proto ./back/protos/*.proto --ts_proto_out=./ --ts_proto_opt=outputServices=grpc-js,env=node,esModuleInterop=true,snakeToCamel=false", "gen:api": "python3 -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./back/protos/api.proto", "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'", @@ -89,7 +83,7 @@ "nodemailer": "^6.9.16", "p-queue-cjs": "7.3.4", "@bufbuild/protobuf": "^2.2.3", - "pstree.remy": "^1.1.8", + "ps-tree": "^1.2.0", "reflect-metadata": "^0.2.2", "sequelize": "^6.37.5", "serve-handler": "^6.1.6", @@ -104,7 +98,9 @@ "ip2region": "2.3.0", "keyv": "^5.2.3", "@keyv/sqlite": "^4.0.1", - "proper-lockfile": "^4.1.2" + "proper-lockfile": "^4.1.2", + "compression": "^1.7.4", + "helmet": "^6.0.1" }, "devDependencies": { "moment": "2.30.1", @@ -138,6 +134,7 @@ "@types/uuid": "^8.3.4", "@types/request-ip": "0.0.41", "@types/proper-lockfile": "^4.1.4", + "@types/ps-tree": "^1.1.6", "@uiw/codemirror-extensions-langs": "^4.21.9", "@uiw/react-codemirror": "^4.21.9", "@umijs/max": "^4.4.4", @@ -176,6 +173,7 @@ "typescript": "5.2.2", "vh-check": "^2.0.5", "virtualizedtableforantd4": "1.3.0", - "yorkie": "^2.0.0" + "@types/compression": "^1.7.2", + "@types/helmet": "^4.0.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 66c6144d..e176ae66 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ dependencies: chokidar: specifier: ^4.0.1 version: 4.0.1 + compression: + specifier: ^1.7.4 + version: 1.7.5 cors: specifier: ^2.8.5 version: 2.8.5 @@ -65,6 +68,9 @@ dependencies: got: specifier: ^11.8.2 version: 11.8.6 + helmet: + specifier: ^6.0.1 + version: 6.2.0 hpagent: specifier: ^1.2.0 version: 1.2.0 @@ -104,9 +110,9 @@ dependencies: proper-lockfile: specifier: ^4.1.2 version: 4.1.2 - pstree.remy: - specifier: ^1.1.8 - version: 1.1.8 + ps-tree: + specifier: ^1.2.0 + version: 1.2.0 reflect-metadata: specifier: ^0.2.2 version: 0.2.2 @@ -163,6 +169,9 @@ devDependencies: '@types/body-parser': specifier: ^1.19.2 version: 1.19.5 + '@types/compression': + specifier: ^1.7.2 + version: 1.7.5 '@types/cors': specifier: ^2.8.12 version: 2.8.17 @@ -178,6 +187,9 @@ devDependencies: '@types/file-saver': specifier: 2.0.2 version: 2.0.2 + '@types/helmet': + specifier: ^4.0.0 + version: 4.0.0 '@types/js-yaml': specifier: ^4.0.5 version: 4.0.9 @@ -202,6 +214,9 @@ devDependencies: '@types/proper-lockfile': specifier: ^4.1.4 version: 4.1.4 + '@types/ps-tree': + specifier: ^1.1.6 + version: 1.1.6 '@types/qrcode.react': specifier: ^1.0.2 version: 1.0.5 @@ -349,9 +364,6 @@ devDependencies: virtualizedtableforantd4: specifier: 1.3.0 version: 1.3.0(antd@4.24.16)(react-dom@18.3.1)(react@18.3.1) - yorkie: - specifier: ^2.0.0 - version: 2.0.0 packages: @@ -3808,6 +3820,12 @@ packages: '@types/responselike': 1.0.3 dev: false + /@types/compression@1.7.5: + resolution: {integrity: sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==} + dependencies: + '@types/express': 4.17.21 + dev: true + /@types/connect@3.4.38: resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} dependencies: @@ -3878,6 +3896,13 @@ packages: resolution: {integrity: sha512-oOMFT8vmCTFncsF1engrs04jatz8/Anwx3De9uxnOK4chgSEgWBvFtpSoJo8u3784JNO+ql5tzRR6phHoRnscQ==} dev: true + /@types/helmet@4.0.0: + resolution: {integrity: sha512-ONIn/nSNQA57yRge3oaMQESef/6QhoeX7llWeDli0UZIfz8TQMkfNPTXA8VnnyeA1WUjG2pGqdjEIueYonMdfQ==} + deprecated: This is a stub types definition. helmet provides its own type definitions, so you do not need this installed. + dependencies: + helmet: 6.2.0 + dev: true + /@types/hoist-non-react-statics@3.3.5: resolution: {integrity: sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==} dependencies: @@ -4011,6 +4036,10 @@ packages: '@types/retry': 0.12.5 dev: true + /@types/ps-tree@1.1.6: + resolution: {integrity: sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ==} + dev: true + /@types/qrcode.react@1.0.5: resolution: {integrity: sha512-BghPtnlwvrvq8QkGa1H25YnN+5OIgCKFuQruncGWLGJYOzeSKiix/4+B9BtfKF2wf5ja8yfyWYA3OXju995G8w==} dependencies: @@ -6144,10 +6173,6 @@ packages: engines: {node: '>=10'} dev: false - /ci-info@1.6.0: - resolution: {integrity: sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==} - dev: true - /ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -6343,7 +6368,6 @@ packages: engines: {node: '>= 0.6'} dependencies: mime-db: 1.53.0 - dev: true /compression-webpack-plugin@9.2.0: resolution: {integrity: sha512-R/Oi+2+UHotGfu72fJiRoVpuRifZT0tTC6UqFD/DUo+mv8dbOow9rVOuTvDv5nPPm3GZhHL/fKkwxwIHnJ8Nyw==} @@ -6371,7 +6395,6 @@ packages: vary: 1.1.2 transitivePeerDependencies: - supports-color - dev: true /compute-scroll-into-view@1.0.20: resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==} @@ -6581,14 +6604,6 @@ packages: engines: {node: '>=6.0'} dev: false - /cross-spawn@5.1.0: - resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} - dependencies: - lru-cache: 4.1.5 - shebang-command: 1.2.0 - which: 1.3.1 - dev: true - /cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -7107,6 +7122,10 @@ packages: detect-libc: 1.0.3 dev: true + /duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + dev: false + /duplexify@4.1.3: resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} dependencies: @@ -7755,6 +7774,18 @@ packages: es5-ext: 0.10.64 dev: true + /event-stream@3.3.4: + resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} + dependencies: + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.1.0 + pause-stream: 0.0.11 + split: 0.3.3 + stream-combiner: 0.0.4 + through: 2.3.8 + dev: false + /eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} dev: false @@ -7785,19 +7816,6 @@ packages: safe-buffer: 5.2.1 dev: true - /execa@0.8.0: - resolution: {integrity: sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==} - engines: {node: '>=4'} - dependencies: - cross-spawn: 5.1.0 - get-stream: 3.0.0 - is-stream: 1.1.0 - npm-run-path: 2.0.2 - p-finally: 1.0.0 - signal-exit: 3.0.7 - strip-eof: 1.0.0 - dev: true - /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -8186,6 +8204,10 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + /from@0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + dev: false + /fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -8297,11 +8319,6 @@ packages: engines: {node: '>=10'} dev: true - /get-stream@3.0.0: - resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==} - engines: {node: '>=4'} - dev: true - /get-stream@5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} @@ -8558,6 +8575,10 @@ packages: hasBin: true dev: true + /helmet@6.2.0: + resolution: {integrity: sha512-DWlwuXLLqbrIOltR6tFQXShj/+7Cyp0gLi6uAb8qMdFh/YBBFbKSgQ6nbXmScYd8emMctuthmgIa7tUfo9Rtyg==} + engines: {node: '>=14.0.0'} + /history@5.3.0: resolution: {integrity: sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==} dependencies: @@ -8995,13 +9016,6 @@ packages: engines: {node: '>= 0.4'} dev: true - /is-ci@1.2.1: - resolution: {integrity: sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==} - hasBin: true - dependencies: - ci-info: 1.6.0 - dev: true - /is-core-module@2.15.1: resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} engines: {node: '>= 0.4'} @@ -9190,11 +9204,6 @@ packages: call-bind: 1.0.7 dev: true - /is-stream@1.1.0: - resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} - engines: {node: '>=0.10.0'} - dev: true - /is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -9883,13 +9892,6 @@ packages: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} dev: true - /lru-cache@4.1.5: - resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} - dependencies: - pseudomap: 1.0.2 - yallist: 2.1.2 - dev: true - /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -9971,6 +9973,10 @@ packages: engines: {node: '>=8'} dev: true + /map-stream@0.1.0: + resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + dev: false + /mathml-tag-names@2.1.3: resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} dev: true @@ -10071,7 +10077,6 @@ packages: /mime-db@1.53.0: resolution: {integrity: sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==} engines: {node: '>= 0.6'} - dev: true /mime-types@2.1.18: resolution: {integrity: sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==} @@ -10521,11 +10526,6 @@ packages: validate-npm-package-license: 3.0.4 dev: true - /normalize-path@1.0.0: - resolution: {integrity: sha512-7WyT0w8jhpDStXRq5836AMmihQwq2nrUVQrgjvUo/p/NZf9uy/MeJ246lBJVmWuYXMlJuG9BNZHF0hWjfTbQUA==} - engines: {node: '>=0.10.0'} - dev: true - /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -10549,13 +10549,6 @@ packages: resolution: {integrity: sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==} dev: true - /npm-run-path@2.0.2: - resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} - engines: {node: '>=4'} - dependencies: - path-key: 2.0.1 - dev: true - /npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} @@ -10695,7 +10688,6 @@ packages: /on-headers@1.0.2: resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} engines: {node: '>= 0.8'} - dev: true /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -10779,11 +10771,6 @@ packages: engines: {node: '>=8'} dev: false - /p-finally@1.0.0: - resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} - engines: {node: '>=4'} - dev: true - /p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -10917,11 +10904,6 @@ packages: resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==} dev: false - /path-key@2.0.1: - resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} - engines: {node: '>=4'} - dev: true - /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -10978,7 +10960,6 @@ packages: resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} dependencies: through: 2.3.8 - dev: true /pbkdf2@3.1.2: resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} @@ -11786,12 +11767,17 @@ packages: dev: true optional: true - /pseudomap@1.0.2: - resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} - dev: true + /ps-tree@1.2.0: + resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} + engines: {node: '>= 0.10'} + hasBin: true + dependencies: + event-stream: 3.3.4 + dev: false /pstree.remy@1.1.8: resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} + dev: true /public-encrypt@4.0.3: resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} @@ -13635,24 +13621,12 @@ packages: resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} dev: true - /shebang-command@1.2.0: - resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} - engines: {node: '>=0.10.0'} - dependencies: - shebang-regex: 1.0.0 - dev: true - /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 - /shebang-regex@1.0.0: - resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} - engines: {node: '>=0.10.0'} - dev: true - /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} @@ -13894,6 +13868,12 @@ packages: engines: {node: '>= 10.x'} dev: true + /split@0.3.3: + resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} + dependencies: + through: 2.3.8 + dev: false + /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true @@ -13953,6 +13933,12 @@ packages: readable-stream: 2.3.8 dev: true + /stream-combiner@0.0.4: + resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} + dependencies: + duplexer: 0.1.2 + dev: false + /stream-http@2.8.3: resolution: {integrity: sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==} dependencies: @@ -14077,11 +14063,6 @@ packages: ansi-regex: 6.1.0 dev: true - /strip-eof@1.0.0: - resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} - engines: {node: '>=0.10.0'} - dev: true - /strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} @@ -14092,11 +14073,6 @@ packages: engines: {node: '>=12'} dev: true - /strip-indent@2.0.0: - resolution: {integrity: sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==} - engines: {node: '>=4'} - dev: true - /strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} @@ -14420,7 +14396,6 @@ packages: /through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: true /timers-browserify@2.0.12: resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} @@ -15341,10 +15316,6 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - /yallist@2.1.2: - resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} - dev: true - /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} dev: true @@ -15393,17 +15364,6 @@ packages: engines: {node: '>=10'} dev: true - /yorkie@2.0.0: - resolution: {integrity: sha512-jcKpkthap6x63MB4TxwCyuIGkV0oYP/YRyuQU5UO0Yz/E/ZAu+653/uov+phdmO54n6BcvFRyyt0RRrWdN2mpw==} - engines: {node: '>=4'} - requiresBuild: true - dependencies: - execa: 0.8.0 - is-ci: 1.2.1 - normalize-path: 1.0.0 - strip-indent: 2.0.0 - dev: true - /zod-validation-error@2.1.0(zod@3.23.8): resolution: {integrity: sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ==} engines: {node: '>=18.0.0'} diff --git a/shell/check.sh b/shell/check.sh index 737c6972..743ba9c9 100755 --- a/shell/check.sh +++ b/shell/check.sh @@ -81,7 +81,6 @@ main() { check_ql check_nginx check_pm2 - reload_update reload_pm2 echo -e "\n=====> 检测结束\n" } diff --git a/shell/share.sh b/shell/share.sh index 7bcc66fa..47d84e56 100755 --- a/shell/share.sh +++ b/shell/share.sh @@ -308,13 +308,6 @@ reload_pm2() { pm2 startOrGracefulReload ecosystem.config.js } -reload_update() { - cd $dir_root - restore_env_vars - pm2 flush &>/dev/null - pm2 startOrGracefulReload other.config.js -} - diff_time() { local format="$1" local begin_time="$2" diff --git a/shell/update.sh b/shell/update.sh index 6d161ad7..5c4e1c12 100755 --- a/shell/update.sh +++ b/shell/update.sh @@ -227,7 +227,10 @@ usage() { } reload_qinglong() { + echo -e "[reload_qinglong] deleting Triggered at $(date)" >>${dir_log}/reload.log + sleep 3 delete_pm2 + echo -e "[reload_qinglong] deleted Triggered at $(date)" >>${dir_log}/reload.log local reload_target="${1}" local primary_branch="master" @@ -247,8 +250,9 @@ reload_qinglong() { rm -rf ${dir_data}/* mv -f ${dir_tmp}/data/* ${dir_data}/ fi - + echo -e "[reload_qinglong] starting Triggered at $(date)" >>${dir_log}/reload.log reload_pm2 + echo -e "[reload_qinglong] started Triggered at $(date)\n" >>${dir_log}/reload.log } ## 更新 qinglong @@ -309,15 +313,7 @@ check_update_dep() { echo -e "更新包下载成功..." if [[ "$needRestart" == 'true' ]]; then - delete_pm2 - - rm -rf ${dir_root}/back ${dir_root}/cli ${dir_root}/docker ${dir_root}/sample ${dir_root}/shell ${dir_root}/src - mv -f ${dir_tmp}/qinglong-${primary_branch}/* ${dir_root}/ - rm -rf $dir_static/* - mv -f ${dir_tmp}/qinglong-static-${primary_branch}/* ${dir_static}/ - cp -f $file_config_sample $dir_config/config.sample.sh - - reload_pm2 + reload_qinglong "system" fi else echo -e "\n依赖检测安装失败,请检查网络...\n" diff --git a/src/layouts/index.tsx b/src/layouts/index.tsx index 48c5953a..74ae3cf8 100644 --- a/src/layouts/index.tsx +++ b/src/layouts/index.tsx @@ -101,9 +101,9 @@ export default function () { const getHealthStatus = () => { request - .get(`${config.apiPrefix}public/health`) + .get(`${config.apiPrefix}health`) .then((res) => { - if (res?.data?.status === 1) { + if (res?.data?.status === 'ok') { getSystemInfo(); } else { history.push('/error'); diff --git a/src/pages/error/index.tsx b/src/pages/error/index.tsx index 430a8c53..216b584c 100644 --- a/src/pages/error/index.tsx +++ b/src/pages/error/index.tsx @@ -17,9 +17,9 @@ const Error = () => { const getHealthStatus = (needLoading: boolean = true) => { needLoading && setLoading(true); request - .get(`${config.apiPrefix}public/health`) + .get(`${config.apiPrefix}health`) .then(({ error, data }) => { - if (data?.status === 1) { + if (data?.status === 'ok') { if (retryTimes.current > 1) { setTimeout(() => { window.location.reload(); diff --git a/src/utils/codemirror/systemLog.ts b/src/utils/codemirror/systemLog.ts index 4d4af67e..6499c49c 100644 --- a/src/utils/codemirror/systemLog.ts +++ b/src/utils/codemirror/systemLog.ts @@ -6,10 +6,10 @@ import { } from '@codemirror/view'; import { RangeSet, RangeSetBuilder } from '@codemirror/state'; -const infoWord = /\[\ue6f5info\]/g; -const debugWord = /\[\ue67fdebug\]/g; -const warnWord = /\[\ue880warn\]/g; -const errorWord = /\[\ue602error\]/g; +const infoWord = /\[ℹ️info/g; +const debugWord = /\[⚠️debug/g; +const warnWord = /\[❌warn/g; +const errorWord = /\[🐛error/g; const customWordClassMap = { info: 'system-log-info',