mirror of
https://github.com/whyour/qinglong.git
synced 2025-05-22 14:26:07 +08:00
修改服务启动逻辑
This commit is contained in:
parent
729b405b0f
commit
d871585eee
16
.env.example
16
.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=
|
||||
|
|
10
.umirc.ts
10
.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,
|
||||
|
|
9
back.d.ts
vendored
9
back.d.ts
vendored
|
@ -1,9 +0,0 @@
|
|||
import 'express';
|
||||
|
||||
declare global {
|
||||
namespace Express {
|
||||
interface Request {
|
||||
platform: string;
|
||||
}
|
||||
}
|
||||
}
|
27
back/api/health.ts
Normal file
27
back/api/health.ts
Normal file
|
@ -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,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
|
@ -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;
|
||||
};
|
||||
|
|
51
back/api/update.ts
Normal file
51
back/api/update.ts
Normal file
|
@ -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);
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
100
back/app.ts
100
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);
|
||||
});
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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<number[]> {
|
||||
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)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
7
back/index.d.ts
vendored
7
back/index.d.ts
vendored
|
@ -1,7 +0,0 @@
|
|||
declare namespace Express {
|
||||
interface Request {
|
||||
platform: 'desktop' | 'mobile';
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'pstree.remy';
|
|
@ -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');
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -122,5 +122,4 @@ export default async () => {
|
|||
}
|
||||
|
||||
Logger.info('✌️ Init file down');
|
||||
console.log('✌️ Init file down');
|
||||
};
|
||||
|
|
|
@ -4,35 +4,60 @@ import config from '../config';
|
|||
import path from 'path';
|
||||
|
||||
const levelMap: Record<string, string> = {
|
||||
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;
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
80
back/middlewares/monitoring.ts
Normal file
80
back/middlewares/monitoring.ts
Normal file
|
@ -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<string, number>),
|
||||
requestsByPlatform: requestMetrics.reduce((acc, curr) => {
|
||||
if (curr.platform) {
|
||||
acc[curr.platform] = (acc[curr.platform] || 0) + 1;
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, number>),
|
||||
recentRequests: requestMetrics.slice(-10),
|
||||
};
|
||||
};
|
|
@ -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);
|
||||
});
|
|
@ -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 },
|
||||
);
|
||||
|
|
|
@ -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');
|
||||
},
|
||||
);
|
64
back/services/grpc.ts
Normal file
64
back/services/grpc.ts
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
72
back/services/health.ts
Normal file
72
back/services/health.ts
Normal file
|
@ -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<HealthStatus> {
|
||||
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;
|
||||
}
|
||||
}
|
53
back/services/http.ts
Normal file
53
back/services/http.ts
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
92
back/services/metrics.ts
Normal file
92
back/services/metrics.ts
Normal file
|
@ -0,0 +1,92 @@
|
|||
import { performance } from 'perf_hooks';
|
||||
import Logger from '../loaders/logger';
|
||||
|
||||
interface Metric {
|
||||
name: string;
|
||||
value: number;
|
||||
timestamp: number;
|
||||
tags?: Record<string, string>;
|
||||
}
|
||||
|
||||
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<string, string>) {
|
||||
this.metrics.push({
|
||||
name,
|
||||
value,
|
||||
timestamp: Date.now(),
|
||||
tags,
|
||||
});
|
||||
}
|
||||
|
||||
measure(name: string, fn: () => void, tags?: Record<string, string>) {
|
||||
const start = performance.now();
|
||||
try {
|
||||
fn();
|
||||
} finally {
|
||||
const duration = performance.now() - start;
|
||||
this.record(name, duration, tags);
|
||||
}
|
||||
}
|
||||
|
||||
async measureAsync(name: string, fn: () => Promise<void>, tags?: Record<string, string>) {
|
||||
const start = performance.now();
|
||||
try {
|
||||
await fn();
|
||||
} finally {
|
||||
const duration = performance.now() - start;
|
||||
this.record(name, duration, tags);
|
||||
}
|
||||
}
|
||||
|
||||
getMetrics(name?: string, tags?: Record<string, string>) {
|
||||
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();
|
|
@ -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 };
|
||||
}
|
||||
|
||||
|
|
|
@ -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, {
|
||||
|
|
|
@ -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 },
|
||||
);
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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"]
|
||||
}
|
11
back/types/express.d.ts
vendored
Normal file
11
back/types/express.d.ts
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
/// <reference types="express" />
|
||||
|
||||
export {};
|
||||
|
||||
declare global {
|
||||
namespace Express {
|
||||
interface Request {
|
||||
platform: 'desktop' | 'mobile';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
|
@ -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"]
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
],
|
||||
};
|
18
package.json
18
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"
|
||||
}
|
||||
}
|
||||
|
|
206
pnpm-lock.yaml
206
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'}
|
||||
|
|
|
@ -81,7 +81,6 @@ main() {
|
|||
check_ql
|
||||
check_nginx
|
||||
check_pm2
|
||||
reload_update
|
||||
reload_pm2
|
||||
echo -e "\n=====> 检测结束\n"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue
Block a user