mirror of
https://github.com/whyour/qinglong.git
synced 2026-08-12 19:30:48 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddee69d291 | ||
|
|
28960c9fab | ||
|
|
449301e519 | ||
|
|
28dab3dc2f | ||
|
|
7995d98db5 | ||
|
|
1f319f3533 | ||
|
|
7d2dbaa62d | ||
|
|
ed5999526b | ||
|
|
2409f75491 | ||
|
|
0c840095d1 | ||
|
|
3eaf0b4856 | ||
|
|
394735a5d9 | ||
|
|
5bfa10bfe7 |
+4
-4
@@ -8,10 +8,10 @@ import { celebrate, Joi } from 'celebrate';
|
|||||||
const route = Router();
|
const route = Router();
|
||||||
|
|
||||||
export default (app: Router) => {
|
export default (app: Router) => {
|
||||||
app.use('/', route);
|
app.use('/configs', route);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/configs/files',
|
'/files',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
@@ -32,7 +32,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/configs/:file',
|
'/:file',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
@@ -58,7 +58,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.post(
|
route.post(
|
||||||
'/configs/save',
|
'/save',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
name: Joi.string().required(),
|
name: Joi.string().required(),
|
||||||
|
|||||||
+26
-30
@@ -7,26 +7,22 @@ import cron_parser from 'cron-parser';
|
|||||||
const route = Router();
|
const route = Router();
|
||||||
|
|
||||||
export default (app: Router) => {
|
export default (app: Router) => {
|
||||||
app.use('/', route);
|
app.use('/crons', route);
|
||||||
route.get(
|
|
||||||
'/crons',
|
route.get('/', async (req: Request, res: Response, next: NextFunction) => {
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
const logger: Logger = Container.get('logger');
|
||||||
const logger: Logger = Container.get('logger');
|
try {
|
||||||
try {
|
const cronService = Container.get(CronService);
|
||||||
const cronService = Container.get(CronService);
|
const data = await cronService.crontabs(req.query.searchValue as string);
|
||||||
const data = await cronService.crontabs(
|
return res.send({ code: 200, data });
|
||||||
req.query.searchValue as string,
|
} catch (e) {
|
||||||
);
|
logger.error('🔥 error: %o', e);
|
||||||
return res.send({ code: 200, data });
|
return next(e);
|
||||||
} catch (e) {
|
}
|
||||||
logger.error('🔥 error: %o', e);
|
});
|
||||||
return next(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
route.post(
|
route.post(
|
||||||
'/crons',
|
'/',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
command: Joi.string().required(),
|
command: Joi.string().required(),
|
||||||
@@ -52,7 +48,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/crons/run',
|
'/run',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
@@ -70,7 +66,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/crons/stop',
|
'/stop',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
@@ -88,7 +84,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/crons/disable',
|
'/disable',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
@@ -106,7 +102,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/crons/enable',
|
'/enable',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
@@ -124,7 +120,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/crons/:id/log',
|
'/:id/log',
|
||||||
celebrate({
|
celebrate({
|
||||||
params: Joi.object({
|
params: Joi.object({
|
||||||
id: Joi.string().required(),
|
id: Joi.string().required(),
|
||||||
@@ -144,7 +140,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/crons',
|
'',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
command: Joi.string().optional(),
|
command: Joi.string().optional(),
|
||||||
@@ -174,7 +170,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.delete(
|
route.delete(
|
||||||
'/crons',
|
'/',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
@@ -192,7 +188,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/crons/pin',
|
'/pin',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
@@ -210,7 +206,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/crons/unpin',
|
'/unpin',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
@@ -228,7 +224,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/crons/import',
|
'/import',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
@@ -243,7 +239,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/crons/:id',
|
'/:id',
|
||||||
celebrate({
|
celebrate({
|
||||||
params: Joi.object({
|
params: Joi.object({
|
||||||
id: Joi.string().required(),
|
id: Joi.string().required(),
|
||||||
@@ -263,7 +259,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/crons/status',
|
'/status',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
ids: Joi.array().items(Joi.string().required()),
|
ids: Joi.array().items(Joi.string().required()),
|
||||||
|
|||||||
+19
-21
@@ -6,24 +6,22 @@ import { celebrate, Joi } from 'celebrate';
|
|||||||
const route = Router();
|
const route = Router();
|
||||||
|
|
||||||
export default (app: Router) => {
|
export default (app: Router) => {
|
||||||
app.use('/', route);
|
app.use('/dependencies', route);
|
||||||
route.get(
|
|
||||||
'/dependencies',
|
route.get('/', async (req: Request, res: Response, next: NextFunction) => {
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
const logger: Logger = Container.get('logger');
|
||||||
const logger: Logger = Container.get('logger');
|
try {
|
||||||
try {
|
const dependenceService = Container.get(DependenceService);
|
||||||
const dependenceService = Container.get(DependenceService);
|
const data = await dependenceService.dependencies(req.query as any);
|
||||||
const data = await dependenceService.dependencies(req.query as any);
|
return res.send({ code: 200, data });
|
||||||
return res.send({ code: 200, data });
|
} catch (e) {
|
||||||
} catch (e) {
|
logger.error('🔥 error: %o', e);
|
||||||
logger.error('🔥 error: %o', e);
|
return next(e);
|
||||||
return next(e);
|
}
|
||||||
}
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
route.post(
|
route.post(
|
||||||
'/dependencies',
|
'/',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(
|
body: Joi.array().items(
|
||||||
Joi.object({
|
Joi.object({
|
||||||
@@ -47,7 +45,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/dependencies',
|
'/',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
name: Joi.string().required(),
|
name: Joi.string().required(),
|
||||||
@@ -70,7 +68,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.delete(
|
route.delete(
|
||||||
'/dependencies',
|
'/',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
@@ -88,7 +86,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.delete(
|
route.delete(
|
||||||
'/dependencies/force',
|
'/force',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
@@ -106,7 +104,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/dependencies/:id',
|
'/:id',
|
||||||
celebrate({
|
celebrate({
|
||||||
params: Joi.object({
|
params: Joi.object({
|
||||||
id: Joi.string().required(),
|
id: Joi.string().required(),
|
||||||
@@ -126,7 +124,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/dependencies/reinstall',
|
'/reinstall',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
|
|||||||
+21
-23
@@ -6,24 +6,22 @@ import { celebrate, Joi } from 'celebrate';
|
|||||||
const route = Router();
|
const route = Router();
|
||||||
|
|
||||||
export default (app: Router) => {
|
export default (app: Router) => {
|
||||||
app.use('/', route);
|
app.use('/envs', route);
|
||||||
route.get(
|
|
||||||
'/envs',
|
route.get('/', async (req: Request, res: Response, next: NextFunction) => {
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
const logger: Logger = Container.get('logger');
|
||||||
const logger: Logger = Container.get('logger');
|
try {
|
||||||
try {
|
const envService = Container.get(EnvService);
|
||||||
const envService = Container.get(EnvService);
|
const data = await envService.envs(req.query.searchValue as string);
|
||||||
const data = await envService.envs(req.query.searchValue as string);
|
return res.send({ code: 200, data });
|
||||||
return res.send({ code: 200, data });
|
} catch (e) {
|
||||||
} catch (e) {
|
logger.error('🔥 error: %o', e);
|
||||||
logger.error('🔥 error: %o', e);
|
return next(e);
|
||||||
return next(e);
|
}
|
||||||
}
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
route.post(
|
route.post(
|
||||||
'/envs',
|
'/',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(
|
body: Joi.array().items(
|
||||||
Joi.object({
|
Joi.object({
|
||||||
@@ -47,7 +45,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/envs',
|
'/',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
value: Joi.string().required(),
|
value: Joi.string().required(),
|
||||||
@@ -70,7 +68,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.delete(
|
route.delete(
|
||||||
'/envs',
|
'/',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
@@ -88,7 +86,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/envs/:id/move',
|
'/:id/move',
|
||||||
celebrate({
|
celebrate({
|
||||||
params: Joi.object({
|
params: Joi.object({
|
||||||
id: Joi.string().required(),
|
id: Joi.string().required(),
|
||||||
@@ -112,7 +110,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/envs/disable',
|
'/disable',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
@@ -130,7 +128,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/envs/enable',
|
'/enable',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.array().items(Joi.string().required()),
|
body: Joi.array().items(Joi.string().required()),
|
||||||
}),
|
}),
|
||||||
@@ -148,7 +146,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/envs/name',
|
'/name',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
ids: Joi.array().items(Joi.string().required()),
|
ids: Joi.array().items(Joi.string().required()),
|
||||||
@@ -169,7 +167,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/envs/:id',
|
'/:id',
|
||||||
celebrate({
|
celebrate({
|
||||||
params: Joi.object({
|
params: Joi.object({
|
||||||
id: Joi.string().required(),
|
id: Joi.string().required(),
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import cron from './cron';
|
|||||||
import script from './script';
|
import script from './script';
|
||||||
import open from './open';
|
import open from './open';
|
||||||
import dependence from './dependence';
|
import dependence from './dependence';
|
||||||
|
import system from './system';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const app = Router();
|
const app = Router();
|
||||||
@@ -18,6 +19,7 @@ export default () => {
|
|||||||
script(app);
|
script(app);
|
||||||
open(app);
|
open(app);
|
||||||
dependence(app);
|
dependence(app);
|
||||||
|
system(app);
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
};
|
};
|
||||||
|
|||||||
+33
-35
@@ -7,44 +7,42 @@ import { getFileContentByName } from '../config/util';
|
|||||||
const route = Router();
|
const route = Router();
|
||||||
|
|
||||||
export default (app: Router) => {
|
export default (app: Router) => {
|
||||||
app.use('/', route);
|
app.use('/logs', route);
|
||||||
route.get(
|
|
||||||
'/logs',
|
route.get('/', async (req: Request, res: Response, next: NextFunction) => {
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
const logger: Logger = Container.get('logger');
|
||||||
const logger: Logger = Container.get('logger');
|
try {
|
||||||
try {
|
const fileList = fs.readdirSync(config.logPath, 'utf-8');
|
||||||
const fileList = fs.readdirSync(config.logPath, 'utf-8');
|
const dirs = [];
|
||||||
const dirs = [];
|
for (let i = 0; i < fileList.length; i++) {
|
||||||
for (let i = 0; i < fileList.length; i++) {
|
const stat = fs.lstatSync(config.logPath + fileList[i]);
|
||||||
const stat = fs.lstatSync(config.logPath + fileList[i]);
|
if (stat.isDirectory()) {
|
||||||
if (stat.isDirectory()) {
|
const fileListTmp = fs.readdirSync(
|
||||||
const fileListTmp = fs.readdirSync(
|
`${config.logPath}/${fileList[i]}`,
|
||||||
`${config.logPath}/${fileList[i]}`,
|
'utf-8',
|
||||||
'utf-8',
|
);
|
||||||
);
|
dirs.push({
|
||||||
dirs.push({
|
name: fileList[i],
|
||||||
name: fileList[i],
|
isDir: true,
|
||||||
isDir: true,
|
files: fileListTmp.reverse(),
|
||||||
files: fileListTmp.reverse(),
|
});
|
||||||
});
|
} else {
|
||||||
} else {
|
dirs.push({
|
||||||
dirs.push({
|
name: fileList[i],
|
||||||
name: fileList[i],
|
isDir: false,
|
||||||
isDir: false,
|
files: [],
|
||||||
files: [],
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
res.send({ code: 200, dirs });
|
|
||||||
} catch (e) {
|
|
||||||
logger.error('🔥 error: %o', e);
|
|
||||||
return next(e);
|
|
||||||
}
|
}
|
||||||
},
|
res.send({ code: 200, dirs });
|
||||||
);
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/logs/:dir/:file',
|
'/:dir/:file',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
@@ -61,7 +59,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/logs/:file',
|
'/:file',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
|
|||||||
+34
-8
@@ -14,10 +14,10 @@ import ScriptService from '../services/script';
|
|||||||
const route = Router();
|
const route = Router();
|
||||||
|
|
||||||
export default (app: Router) => {
|
export default (app: Router) => {
|
||||||
app.use('/', route);
|
app.use('/scripts', route);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/scripts/files',
|
'/files',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
@@ -80,7 +80,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/scripts/:file',
|
'/:file',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
@@ -99,7 +99,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.post(
|
route.post(
|
||||||
'/scripts',
|
'/',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
filename: Joi.string().required(),
|
filename: Joi.string().required(),
|
||||||
@@ -159,7 +159,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/scripts',
|
'/',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
filename: Joi.string().required(),
|
filename: Joi.string().required(),
|
||||||
@@ -186,7 +186,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.delete(
|
route.delete(
|
||||||
'/scripts',
|
'/',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
filename: Joi.string().required(),
|
filename: Joi.string().required(),
|
||||||
@@ -211,7 +211,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.post(
|
route.post(
|
||||||
'/scripts/download',
|
'/download',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
filename: Joi.string().required(),
|
filename: Joi.string().required(),
|
||||||
@@ -242,7 +242,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/scripts/run',
|
'/run',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
filename: Joi.string().required(),
|
filename: Joi.string().required(),
|
||||||
@@ -266,4 +266,30 @@ export default (app: Router) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
route.put(
|
||||||
|
'/stop',
|
||||||
|
celebrate({
|
||||||
|
body: Joi.object({
|
||||||
|
filename: Joi.string().required(),
|
||||||
|
path: Joi.string().optional().allow(''),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
let { filename, path } = req.body as {
|
||||||
|
filename: string;
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
const filePath = join(path, filename);
|
||||||
|
const scriptService = Container.get(ScriptService);
|
||||||
|
const result = await scriptService.stopScript(filePath);
|
||||||
|
res.send(result);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import { Router, Request, Response, NextFunction } from 'express';
|
||||||
|
import { Container } from 'typedi';
|
||||||
|
import { Logger } from 'winston';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import config from '../config';
|
||||||
|
import SystemService from '../services/system';
|
||||||
|
import { celebrate, Joi } from 'celebrate';
|
||||||
|
import { getFileContentByName } from '../config/util';
|
||||||
|
import UserService from '../services/user';
|
||||||
|
const route = Router();
|
||||||
|
|
||||||
|
export default (app: Router) => {
|
||||||
|
app.use('/system', route);
|
||||||
|
|
||||||
|
route.get('/', async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
const userService = Container.get(UserService);
|
||||||
|
const authInfo = await userService.getUserInfo();
|
||||||
|
const envDbContent = getFileContentByName(config.envDbFile);
|
||||||
|
const versionRegx = /.*export const version = \'(.*)\'\;/;
|
||||||
|
|
||||||
|
const currentVersionFile = fs.readFileSync(config.versionFile, 'utf8');
|
||||||
|
const version = currentVersionFile.match(versionRegx)![1];
|
||||||
|
|
||||||
|
let isInitialized = true;
|
||||||
|
if (
|
||||||
|
Object.keys(authInfo).length === 2 &&
|
||||||
|
authInfo.username === 'admin' &&
|
||||||
|
authInfo.password === 'admin' &&
|
||||||
|
envDbContent.length === 0
|
||||||
|
) {
|
||||||
|
isInitialized = false;
|
||||||
|
}
|
||||||
|
res.send({
|
||||||
|
code: 200,
|
||||||
|
data: {
|
||||||
|
isInitialized,
|
||||||
|
version,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
route.get(
|
||||||
|
'/log/remove',
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
const systemService = Container.get(SystemService);
|
||||||
|
const data = await systemService.getLogRemoveFrequency();
|
||||||
|
res.send({ code: 200, data });
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
route.put(
|
||||||
|
'/log/remove',
|
||||||
|
celebrate({
|
||||||
|
body: Joi.object({
|
||||||
|
frequency: Joi.number().required(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
const systemService = Container.get(SystemService);
|
||||||
|
const result = await systemService.updateLogRemoveFrequency(
|
||||||
|
req.body.frequency,
|
||||||
|
);
|
||||||
|
res.send(result);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
route.put(
|
||||||
|
'/update-check',
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
const systemService = Container.get(SystemService);
|
||||||
|
const result = await systemService.checkUpdate();
|
||||||
|
res.send(result);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
route.put(
|
||||||
|
'/update',
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const logger: Logger = Container.get('logger');
|
||||||
|
try {
|
||||||
|
const systemService = Container.get(SystemService);
|
||||||
|
const result = await systemService.updateSystem();
|
||||||
|
res.send(result);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('🔥 error: %o', e);
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
+29
-130
@@ -9,7 +9,8 @@ import { getFileContentByName } from '../config/util';
|
|||||||
const route = Router();
|
const route = Router();
|
||||||
|
|
||||||
export default (app: Router) => {
|
export default (app: Router) => {
|
||||||
app.use('/', route);
|
app.use('/user', route);
|
||||||
|
|
||||||
route.post(
|
route.post(
|
||||||
'/login',
|
'/login',
|
||||||
celebrate({
|
celebrate({
|
||||||
@@ -47,7 +48,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/user',
|
'/',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
username: Joi.string().required(),
|
username: Joi.string().required(),
|
||||||
@@ -67,29 +68,26 @@ export default (app: Router) => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
route.get('/', async (req: Request, res: Response, next: NextFunction) => {
|
||||||
'/user',
|
const logger: Logger = Container.get('logger');
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
try {
|
||||||
const logger: Logger = Container.get('logger');
|
const userService = Container.get(UserService);
|
||||||
try {
|
const authInfo = await userService.getUserInfo();
|
||||||
const userService = Container.get(UserService);
|
res.send({
|
||||||
const authInfo = await userService.getUserInfo();
|
code: 200,
|
||||||
res.send({
|
data: {
|
||||||
code: 200,
|
username: authInfo.username,
|
||||||
data: {
|
twoFactorActivated: authInfo.twoFactorActivated,
|
||||||
username: authInfo.username,
|
},
|
||||||
twoFactorActivated: authInfo.twoFactorActivated,
|
});
|
||||||
},
|
} catch (e) {
|
||||||
});
|
logger.error('🔥 error: %o', e);
|
||||||
} catch (e) {
|
return next(e);
|
||||||
logger.error('🔥 error: %o', e);
|
}
|
||||||
return next(e);
|
});
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/user/two-factor/init',
|
'/two-factor/init',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
@@ -104,7 +102,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/user/two-factor/active',
|
'/two-factor/active',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
code: Joi.string().required(),
|
code: Joi.string().required(),
|
||||||
@@ -124,7 +122,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/user/two-factor/deactive',
|
'/two-factor/deactive',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
@@ -139,7 +137,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/user/two-factor/login',
|
'/two-factor/login',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
code: Joi.string().required(),
|
code: Joi.string().required(),
|
||||||
@@ -161,7 +159,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/user/login-log',
|
'/login-log',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
@@ -176,7 +174,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
route.get(
|
||||||
'/user/notification',
|
'/notification',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
@@ -191,7 +189,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/user/notification',
|
'/notification',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
@@ -205,40 +203,8 @@ export default (app: Router) => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
|
||||||
'/system',
|
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
|
||||||
const logger: Logger = Container.get('logger');
|
|
||||||
try {
|
|
||||||
const userService = Container.get(UserService);
|
|
||||||
const authInfo = await userService.getUserInfo();
|
|
||||||
const envDbContent = getFileContentByName(config.envDbFile);
|
|
||||||
|
|
||||||
let isInitialized = true;
|
|
||||||
if (
|
|
||||||
Object.keys(authInfo).length === 2 &&
|
|
||||||
authInfo.username === 'admin' &&
|
|
||||||
authInfo.password === 'admin' &&
|
|
||||||
envDbContent.length === 0
|
|
||||||
) {
|
|
||||||
isInitialized = false;
|
|
||||||
}
|
|
||||||
res.send({
|
|
||||||
code: 200,
|
|
||||||
data: {
|
|
||||||
isInitialized,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
logger.error('🔥 error: %o', e);
|
|
||||||
return next(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// 初始化api
|
|
||||||
route.put(
|
route.put(
|
||||||
'/init/user',
|
'/init',
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
username: Joi.string().required(),
|
username: Joi.string().required(),
|
||||||
@@ -259,7 +225,7 @@ export default (app: Router) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
route.put(
|
route.put(
|
||||||
'/init/notification',
|
'/notification/init',
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
@@ -272,71 +238,4 @@ export default (app: Router) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
route.get(
|
|
||||||
'/system/log/remove',
|
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
|
||||||
const logger: Logger = Container.get('logger');
|
|
||||||
try {
|
|
||||||
const userService = Container.get(UserService);
|
|
||||||
const data = await userService.getLogRemoveFrequency();
|
|
||||||
res.send({ code: 200, data });
|
|
||||||
} catch (e) {
|
|
||||||
logger.error('🔥 error: %o', e);
|
|
||||||
return next(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
route.put(
|
|
||||||
'/system/log/remove',
|
|
||||||
celebrate({
|
|
||||||
body: Joi.object({
|
|
||||||
frequency: Joi.number().required(),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
|
||||||
const logger: Logger = Container.get('logger');
|
|
||||||
try {
|
|
||||||
const userService = Container.get(UserService);
|
|
||||||
const result = await userService.updateLogRemoveFrequency(
|
|
||||||
req.body.frequency,
|
|
||||||
);
|
|
||||||
res.send(result);
|
|
||||||
} catch (e) {
|
|
||||||
logger.error('🔥 error: %o', e);
|
|
||||||
return next(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
route.put(
|
|
||||||
'/system/update-check',
|
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
|
||||||
const logger: Logger = Container.get('logger');
|
|
||||||
try {
|
|
||||||
const userService = Container.get(UserService);
|
|
||||||
const result = await userService.checkUpdate();
|
|
||||||
res.send(result);
|
|
||||||
} catch (e) {
|
|
||||||
logger.error('🔥 error: %o', e);
|
|
||||||
return next(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
route.put(
|
|
||||||
'/system/update',
|
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
|
||||||
const logger: Logger = Container.get('logger');
|
|
||||||
try {
|
|
||||||
const userService = Container.get(UserService);
|
|
||||||
const result = await userService.updateSystem();
|
|
||||||
res.send(result);
|
|
||||||
} catch (e) {
|
|
||||||
logger.error('🔥 error: %o', e);
|
|
||||||
return next(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -77,12 +77,12 @@ export default {
|
|||||||
writePathList: [configPath, scriptPath],
|
writePathList: [configPath, scriptPath],
|
||||||
bakPath,
|
bakPath,
|
||||||
apiWhiteList: [
|
apiWhiteList: [
|
||||||
'/api/login',
|
'/api/user/login',
|
||||||
'/open/auth/token',
|
'/open/auth/token',
|
||||||
'/api/user/two-factor/login',
|
'/api/user/two-factor/login',
|
||||||
'/api/system',
|
'/api/system',
|
||||||
'/api/init/user',
|
'/api/user/init',
|
||||||
'/api/init/notification',
|
'/api/user/notification/init',
|
||||||
],
|
],
|
||||||
versionFile,
|
versionFile,
|
||||||
lastVersionFile,
|
lastVersionFile,
|
||||||
|
|||||||
@@ -231,3 +231,40 @@ export async function fileExist(file: any) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function concurrentRun(
|
||||||
|
fnList: Array<() => Promise<any>> = [],
|
||||||
|
max = 5,
|
||||||
|
) {
|
||||||
|
if (!fnList.length) return;
|
||||||
|
|
||||||
|
const replyList: any[] = []; // 收集任务执行结果
|
||||||
|
const startTime = new Date().getTime(); // 记录任务执行开始时间
|
||||||
|
|
||||||
|
// 任务执行程序
|
||||||
|
const schedule = async (index: number) => {
|
||||||
|
return new Promise(async (resolve) => {
|
||||||
|
const fn = fnList[index];
|
||||||
|
if (!fn) return resolve(null);
|
||||||
|
|
||||||
|
// 执行当前异步任务
|
||||||
|
const reply = await fn();
|
||||||
|
replyList[index] = reply;
|
||||||
|
|
||||||
|
// 执行完当前任务后,继续执行任务池的剩余任务
|
||||||
|
await schedule(index + max);
|
||||||
|
resolve(null);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 任务池执行程序
|
||||||
|
const scheduleList = new Array(max)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, index) => schedule(index));
|
||||||
|
|
||||||
|
// 使用 Promise.all 批量执行
|
||||||
|
const r = await Promise.all(scheduleList);
|
||||||
|
const cost = (new Date().getTime() - startTime) / 1000;
|
||||||
|
|
||||||
|
return replyList;
|
||||||
|
}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export default ({ app }: { app: Application }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.use(async (req, res, next) => {
|
app.use(async (req, res, next) => {
|
||||||
if (!['/api/init/user', '/api/init/notification'].includes(req.path)) {
|
if (!['/api/user/init', '/api/user/notification/init'].includes(req.path)) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
const userService = Container.get(UserService);
|
const userService = Container.get(UserService);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import Logger from './logger';
|
|||||||
|
|
||||||
export default ({ expressApp }: { expressApp: Application }) => {
|
export default ({ expressApp }: { expressApp: Application }) => {
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
dsn: 'https://e14681bce55f4849b11024a7d424b711@o1051273.ingest.sentry.io/6047906',
|
dsn: 'https://f4b5b55fb3c645b29a5dc2d70a1a4ef4@o1098464.ingest.sentry.io/6122819',
|
||||||
integrations: [
|
integrations: [
|
||||||
new Sentry.Integrations.Http({ tracing: true }),
|
new Sentry.Integrations.Http({ tracing: true }),
|
||||||
new Tracing.Integrations.Express({ app: expressApp }),
|
new Tracing.Integrations.Express({ app: expressApp }),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Crontab, CrontabStatus } from '../data/cron';
|
|||||||
import { exec, execSync, spawn } from 'child_process';
|
import { exec, execSync, spawn } from 'child_process';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import cron_parser from 'cron-parser';
|
import cron_parser from 'cron-parser';
|
||||||
import { getFileContentByName } from '../config/util';
|
import { getFileContentByName, concurrentRun } from '../config/util';
|
||||||
import PQueue from 'p-queue';
|
import PQueue from 'p-queue';
|
||||||
import { promises, existsSync } from 'fs';
|
import { promises, existsSync } from 'fs';
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
@@ -200,10 +200,10 @@ export default class CronService {
|
|||||||
{ $set: { status: CrontabStatus.queued } },
|
{ $set: { status: CrontabStatus.queued } },
|
||||||
{ multi: true },
|
{ multi: true },
|
||||||
);
|
);
|
||||||
for (let i = 0; i < ids.length; i++) {
|
concurrentRun(
|
||||||
const id = ids[i];
|
ids.map((id) => () => this.runSingle(id)),
|
||||||
this.queue.add(() => this.runSingle(id));
|
10,
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async stop(ids: string[]) {
|
public async stop(ids: string[]) {
|
||||||
@@ -241,7 +241,7 @@ export default class CronService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async killTask(name: string) {
|
public async killTask(name: string) {
|
||||||
let taskCommand = `ps -ef | grep "${name}" | grep -v grep | awk '{print $1}'`;
|
let taskCommand = `ps -ef | grep "${name}" | grep -v grep | awk '{print $1}'`;
|
||||||
const execAsync = promisify(exec);
|
const execAsync = promisify(exec);
|
||||||
try {
|
try {
|
||||||
|
|||||||
+22
-4
@@ -2,21 +2,19 @@ import { Service, Inject } from 'typedi';
|
|||||||
import winston from 'winston';
|
import winston from 'winston';
|
||||||
import { spawn } from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
import SockService from './sock';
|
import SockService from './sock';
|
||||||
|
import CronService from './cron';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class ScriptService {
|
export default class ScriptService {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject('logger') private logger: winston.Logger,
|
@Inject('logger') private logger: winston.Logger,
|
||||||
private sockService: SockService,
|
private sockService: SockService,
|
||||||
|
private cronService: CronService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public async runScript(path: string) {
|
public async runScript(path: string) {
|
||||||
const cp = spawn(`task -l ${path} now`, { shell: '/bin/bash' });
|
const cp = spawn(`task -l ${path} now`, { shell: '/bin/bash' });
|
||||||
|
|
||||||
this.sockService.sendMessage({
|
|
||||||
type: 'manuallyRunScript',
|
|
||||||
message: `开始执行脚本`,
|
|
||||||
});
|
|
||||||
cp.stdout.on('data', (data) => {
|
cp.stdout.on('data', (data) => {
|
||||||
this.sockService.sendMessage({
|
this.sockService.sendMessage({
|
||||||
type: 'manuallyRunScript',
|
type: 'manuallyRunScript',
|
||||||
@@ -38,6 +36,26 @@ export default class ScriptService {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cp.on('close', (err) => {
|
||||||
|
this.sockService.sendMessage({
|
||||||
|
type: 'manuallyRunScript',
|
||||||
|
message: `执行结束`,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return { code: 200 };
|
||||||
|
}
|
||||||
|
|
||||||
|
public async stopScript(path: string) {
|
||||||
|
const err = await this.cronService.killTask(`task -l ${path} now`);
|
||||||
|
const str = err ? `\n${err}` : '';
|
||||||
|
this.sockService.sendMessage({
|
||||||
|
type: 'manuallyRunScript',
|
||||||
|
message: `${str}\n## 执行结束... ${new Date()
|
||||||
|
.toLocaleString('zh', { hour12: false })
|
||||||
|
.replace(' 24:', ' 00:')} `,
|
||||||
|
});
|
||||||
|
|
||||||
return { code: 200 };
|
return { code: 200 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,184 @@
|
|||||||
|
import { Service, Inject } from 'typedi';
|
||||||
|
import winston from 'winston';
|
||||||
|
import config from '../config';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { AuthDataType, AuthInfo, LoginStatus } from '../data/auth';
|
||||||
|
import { NotificationInfo } from '../data/notify';
|
||||||
|
import NotificationService from './notify';
|
||||||
|
import ScheduleService from './schedule';
|
||||||
|
import { spawn } from 'child_process';
|
||||||
|
import SockService from './sock';
|
||||||
|
import got from 'got';
|
||||||
|
import { dbs } from '../loaders/db';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export default class SystemService {
|
||||||
|
@Inject((type) => NotificationService)
|
||||||
|
private notificationService!: NotificationService;
|
||||||
|
private authDb = dbs.authDb;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject('logger') private logger: winston.Logger,
|
||||||
|
private scheduleService: ScheduleService,
|
||||||
|
private sockService: SockService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public async getLogRemoveFrequency() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.authDb
|
||||||
|
.find({ type: AuthDataType.removeLogFrequency })
|
||||||
|
.exec((err, docs) => {
|
||||||
|
if (err || docs.length === 0) {
|
||||||
|
resolve({});
|
||||||
|
} else {
|
||||||
|
resolve(docs[0].info);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async updateAuthDb(payload: AuthInfo): Promise<any> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.authDb.update(
|
||||||
|
{ type: payload.type },
|
||||||
|
{ ...payload },
|
||||||
|
{ upsert: true, returnUpdatedDocs: true },
|
||||||
|
(err, num, doc: any) => {
|
||||||
|
if (err) {
|
||||||
|
resolve({} as NotificationInfo);
|
||||||
|
} else {
|
||||||
|
resolve({ ...doc.info, _id: doc._id });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateNotificationMode(notificationInfo: NotificationInfo) {
|
||||||
|
const code = Math.random().toString().slice(-6);
|
||||||
|
const isSuccess = await this.notificationService.testNotify(
|
||||||
|
notificationInfo,
|
||||||
|
'青龙',
|
||||||
|
`【蛟龙】测试通知 https://t.me/jiao_long`,
|
||||||
|
);
|
||||||
|
if (isSuccess) {
|
||||||
|
const result = await this.updateAuthDb({
|
||||||
|
type: AuthDataType.notification,
|
||||||
|
info: { ...notificationInfo },
|
||||||
|
});
|
||||||
|
return { code: 200, data: { ...result, code } };
|
||||||
|
} else {
|
||||||
|
return { code: 400, data: '通知发送失败,请检查参数' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateLogRemoveFrequency(frequency: number) {
|
||||||
|
const result = await this.updateAuthDb({
|
||||||
|
type: AuthDataType.removeLogFrequency,
|
||||||
|
info: { frequency },
|
||||||
|
});
|
||||||
|
const cron = {
|
||||||
|
_id: result._id,
|
||||||
|
name: '删除日志',
|
||||||
|
command: `ql rmlog ${frequency}`,
|
||||||
|
schedule: `5 23 */${frequency} * *`,
|
||||||
|
};
|
||||||
|
await this.scheduleService.cancelSchedule(cron);
|
||||||
|
if (frequency > 0) {
|
||||||
|
await this.scheduleService.generateSchedule(cron);
|
||||||
|
}
|
||||||
|
return { code: 200, data: { ...cron } };
|
||||||
|
}
|
||||||
|
|
||||||
|
public async checkUpdate() {
|
||||||
|
try {
|
||||||
|
const versionRegx = /.*export const version = \'(.*)\'\;/;
|
||||||
|
const logRegx = /.*export const changeLog = \`((.*\n.*)+)\`;/;
|
||||||
|
|
||||||
|
const currentVersionFile = fs.readFileSync(config.versionFile, 'utf8');
|
||||||
|
const currentVersion = currentVersionFile.match(versionRegx)![1];
|
||||||
|
|
||||||
|
let lastVersion = '';
|
||||||
|
let lastLog = '';
|
||||||
|
try {
|
||||||
|
const result = await Promise.race([
|
||||||
|
got.get(config.lastVersionFile, { timeout: 1000, retry: 0 }),
|
||||||
|
got.get(`https://ghproxy.com/${config.lastVersionFile}`, {
|
||||||
|
timeout: 5000,
|
||||||
|
retry: 0,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
const lastVersionFileContent = result.body;
|
||||||
|
lastVersion = lastVersionFileContent.match(versionRegx)![1];
|
||||||
|
lastLog = lastVersionFileContent.match(logRegx)
|
||||||
|
? lastVersionFileContent.match(logRegx)![1]
|
||||||
|
: '';
|
||||||
|
} catch (error) {}
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
data: {
|
||||||
|
hasNewVersion: this.checkHasNewVersion(currentVersion, lastVersion),
|
||||||
|
lastVersion,
|
||||||
|
lastLog,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
return {
|
||||||
|
code: 400,
|
||||||
|
data: error.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private checkHasNewVersion(curVersion: string, lastVersion: string) {
|
||||||
|
const curArr = curVersion.split('.').map((x) => parseInt(x, 10));
|
||||||
|
const lastArr = lastVersion.split('.').map((x) => parseInt(x, 10));
|
||||||
|
if (curArr[0] < lastArr[0]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (curArr[0] === lastArr[0] && curArr[1] < lastArr[1]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
curArr[0] === lastArr[0] &&
|
||||||
|
curArr[1] === lastArr[1] &&
|
||||||
|
curArr[2] < lastArr[2]
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateSystem() {
|
||||||
|
const cp = spawn('ql -l update', { shell: '/bin/bash' });
|
||||||
|
|
||||||
|
this.sockService.sendMessage({
|
||||||
|
type: 'updateSystemVersion',
|
||||||
|
message: `开始更新系统`,
|
||||||
|
});
|
||||||
|
cp.stdout.on('data', (data) => {
|
||||||
|
this.sockService.sendMessage({
|
||||||
|
type: 'updateSystemVersion',
|
||||||
|
message: data.toString(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
cp.stderr.on('data', (data) => {
|
||||||
|
this.sockService.sendMessage({
|
||||||
|
type: 'updateSystemVersion',
|
||||||
|
message: data.toString(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
cp.on('error', (err) => {
|
||||||
|
this.sockService.sendMessage({
|
||||||
|
type: 'updateSystemVersion',
|
||||||
|
message: JSON.stringify(err),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return { code: 200 };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { CommandModule } from 'yargs';
|
||||||
|
export const updateCommand: CommandModule = {
|
||||||
|
command: 'update',
|
||||||
|
describe: 'Update and restart qinglong',
|
||||||
|
builder: (yargs) => {
|
||||||
|
return yargs.option('repositority', {
|
||||||
|
type: 'string',
|
||||||
|
alias: 'r',
|
||||||
|
describe: `Specify the release warehouse address of the package`,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handler: async (argv) => {},
|
||||||
|
};
|
||||||
+11
-1
@@ -1,3 +1,13 @@
|
|||||||
import * as yargs from 'yargs';
|
import * as yargs from 'yargs';
|
||||||
|
import { green, red } from 'chalk';
|
||||||
|
import { updateCommand } from './commands/update';
|
||||||
|
|
||||||
yargs.help('h').alias('h', 'help').help().argv;
|
yargs
|
||||||
|
.usage('Usage: ql [command] <options>')
|
||||||
|
.command(updateCommand)
|
||||||
|
.fail((err) => {
|
||||||
|
console.error(`${red(err)}`);
|
||||||
|
})
|
||||||
|
.alias('h', 'help')
|
||||||
|
.showHelp()
|
||||||
|
.recommendCommands().argv;
|
||||||
|
|||||||
+20
-7
@@ -264,13 +264,18 @@ run_designated() {
|
|||||||
|
|
||||||
## 运行其他命令
|
## 运行其他命令
|
||||||
run_else() {
|
run_else() {
|
||||||
local log_time=$(date "+%Y-%m-%d-%H-%M-%S")
|
local file_param="$1"
|
||||||
local log_dir_tmp="${1##*/}"
|
define_program "$file_param"
|
||||||
local log_dir="$dir_log/${log_dir_tmp%%.*}"
|
log_time=$(date "+%Y-%m-%d-%H-%M-%S")
|
||||||
|
log_dir_tmp="${file_param##*/}"
|
||||||
|
log_dir_tmp_path="${file_param%%/*}"
|
||||||
|
log_dir_tmp_path="${log_dir_tmp_path##*/}"
|
||||||
|
[[ $log_dir_tmp_path ]] && log_dir_tmp="${log_dir_tmp_path}_${log_dir_tmp}"
|
||||||
|
log_dir="$dir_log/${log_dir_tmp%%.*}"
|
||||||
log_path="$log_dir/$log_time.log"
|
log_path="$log_dir/$log_time.log"
|
||||||
cmd="&>> $log_path"
|
cmd="&>> $log_path"
|
||||||
[[ "$show_log" == "true" ]] && cmd=""
|
[[ "$show_log" == "true" ]] && cmd=""
|
||||||
make_dir "$log_dir"
|
make_dir $log_dir
|
||||||
|
|
||||||
local begin_time=$(date '+%Y-%m-%d %H:%M:%S')
|
local begin_time=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
local begin_timestamp=$(date "+%s" -d "$begin_time")
|
local begin_timestamp=$(date "+%s" -d "$begin_time")
|
||||||
@@ -278,13 +283,21 @@ run_else() {
|
|||||||
eval echo -e "\#\# 开始执行... $begin_time\\\n" $cmd
|
eval echo -e "\#\# 开始执行... $begin_time\\\n" $cmd
|
||||||
[[ -f $task_error_log_path ]] && eval cat $task_error_log_path $cmd
|
[[ -f $task_error_log_path ]] && eval cat $task_error_log_path $cmd
|
||||||
|
|
||||||
local id=$(cat $list_crontab_user | grep -E "$cmd_task $first_param" | perl -pe "s|.*ID=(.*) $cmd_task $first_param\.*|\1|" | head -1 | awk -F " " '{print $1}')
|
local id=$(cat $list_crontab_user | grep -E "$cmd_task $@" | perl -pe "s|.*ID=(.*) $cmd_task $@\.*|\1|" | head -1 | awk -F " " '{print $1}')
|
||||||
[[ $id ]] && update_cron "\"$id\"" "0" "$$" "$log_path" "$begin_timestamp"
|
[[ $id ]] && update_cron "\"$id\"" "0" "$$" "$log_path" "$begin_timestamp"
|
||||||
eval . $file_task_before "$@" $cmd
|
eval . $file_task_before "$@" $cmd
|
||||||
|
|
||||||
eval timeout -k 10s $command_timeout_time "$@" $cmd
|
cd $dir_scripts
|
||||||
|
local relative_path="${file_param%/*}"
|
||||||
|
if [[ ! -z ${relative_path} ]] && [[ ${file_param} =~ "/" ]]; then
|
||||||
|
cd ${relative_path}
|
||||||
|
file_param=${file_param/$relative_path\//}
|
||||||
|
fi
|
||||||
|
|
||||||
eval . $file_task_after "$@" $cmd
|
shift
|
||||||
|
eval timeout -k 10s $command_timeout_time $which_program "$file_param" "$@" $cmd
|
||||||
|
|
||||||
|
eval . $file_task_after "$file_param" "$@" $cmd
|
||||||
local end_time=$(date '+%Y-%m-%d %H:%M:%S')
|
local end_time=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
local end_timestamp=$(date "+%s" -d "$end_time")
|
local end_timestamp=$(date "+%s" -d "$end_time")
|
||||||
local diff_time=$(( $end_timestamp - $begin_timestamp ))
|
local diff_time=$(( $end_timestamp - $begin_timestamp ))
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import * as Sentry from '@sentry/react';
|
|||||||
import { Integrations } from '@sentry/tracing';
|
import { Integrations } from '@sentry/tracing';
|
||||||
|
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
dsn: 'https://ea2fede373244db99c536210b910d9da@o1051273.ingest.sentry.io/6047851',
|
dsn: 'https://3406424fb1dc4813a62d39e844a9d0ac@o1098464.ingest.sentry.io/6122818',
|
||||||
integrations: [new Integrations.BrowserTracing()],
|
integrations: [new Integrations.BrowserTracing()],
|
||||||
release: version,
|
release: version,
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
@@ -44,7 +44,7 @@ export default function (props: any) {
|
|||||||
const [collapsed, setCollapsed] = useState(false);
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
request.post(`${config.apiPrefix}logout`).then(() => {
|
request.post(`${config.apiPrefix}user/logout`).then(() => {
|
||||||
localStorage.removeItem(config.authKey);
|
localStorage.removeItem(config.authKey);
|
||||||
history.push('/login');
|
history.push('/login');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,3 @@
|
|||||||
.ant-table-pagination.ant-pagination {
|
.ant-table-pagination.ant-pagination {
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr {
|
|
||||||
td:nth-child(2) {
|
|
||||||
span {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
|||||||
width: 150,
|
width: 150,
|
||||||
align: 'center' as const,
|
align: 'center' as const,
|
||||||
render: (text: string, record: any) => (
|
render: (text: string, record: any) => (
|
||||||
<span
|
<a
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
goToScriptManager(record);
|
goToScriptManager(record);
|
||||||
}}
|
}}
|
||||||
@@ -90,7 +90,7 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
|||||||
) : (
|
) : (
|
||||||
''
|
''
|
||||||
)}
|
)}
|
||||||
</span>
|
</a>
|
||||||
),
|
),
|
||||||
sorter: {
|
sorter: {
|
||||||
compare: (a: any, b: any) => a.name.localeCompare(b.name),
|
compare: (a: any, b: any) => a.name.localeCompare(b.name),
|
||||||
@@ -335,8 +335,12 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
|||||||
const [tableScrollHeight, setTableScrollHeight] = useState<number>();
|
const [tableScrollHeight, setTableScrollHeight] = useState<number>();
|
||||||
|
|
||||||
const goToScriptManager = (record: any) => {
|
const goToScriptManager = (record: any) => {
|
||||||
const cmd = record.command.split(' ');
|
const cmd = record.command.split(' ') as string[];
|
||||||
if (cmd[0] === 'task') {
|
if (cmd[0] === 'task') {
|
||||||
|
if (cmd[1].startsWith('/ql/scripts')) {
|
||||||
|
cmd[1] = cmd[1].replace('/ql/scripts/', '');
|
||||||
|
}
|
||||||
|
|
||||||
let [p, s] = cmd[1].split('/');
|
let [p, s] = cmd[1].split('/');
|
||||||
if (!s) {
|
if (!s) {
|
||||||
s = p;
|
s = p;
|
||||||
@@ -799,7 +803,7 @@ const Crontab = ({ headerStyle, isPhone }: any) => {
|
|||||||
onSearch={onSearch}
|
onSearch={onSearch}
|
||||||
/>,
|
/>,
|
||||||
<Button key="2" type="primary" onClick={() => addCron()}>
|
<Button key="2" type="primary" onClick={() => addCron()}>
|
||||||
添加任务
|
新建任务
|
||||||
</Button>,
|
</Button>,
|
||||||
]}
|
]}
|
||||||
header={{
|
header={{
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const CronModal = ({
|
|||||||
data: payload,
|
data: payload,
|
||||||
});
|
});
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
message.success(cron ? '更新Cron成功' : '添加Cron成功');
|
message.success(cron ? '更新Cron成功' : '新建Cron成功');
|
||||||
} else {
|
} else {
|
||||||
message.error(data);
|
message.error(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -398,7 +398,7 @@ const Dependence = ({ headerStyle, isPhone, socketMessage }: any) => {
|
|||||||
onSearch={onSearch}
|
onSearch={onSearch}
|
||||||
/>,
|
/>,
|
||||||
<Button key="2" type="primary" onClick={() => addDependence()}>
|
<Button key="2" type="primary" onClick={() => addDependence()}>
|
||||||
添加依赖
|
新建依赖
|
||||||
</Button>,
|
</Button>,
|
||||||
]}
|
]}
|
||||||
header={{
|
header={{
|
||||||
|
|||||||
Vendored
+1
-1
@@ -485,7 +485,7 @@ const Env = ({ headerStyle, isPhone, theme }: any) => {
|
|||||||
onSearch={onSearch}
|
onSearch={onSearch}
|
||||||
/>,
|
/>,
|
||||||
<Button key="2" type="primary" onClick={() => addEnv()}>
|
<Button key="2" type="primary" onClick={() => addEnv()}>
|
||||||
添加变量
|
新建变量
|
||||||
</Button>,
|
</Button>,
|
||||||
]}
|
]}
|
||||||
header={{
|
header={{
|
||||||
|
|||||||
Vendored
+1
-1
@@ -40,7 +40,7 @@ const EnvModal = ({
|
|||||||
data: payload,
|
data: payload,
|
||||||
});
|
});
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
message.success(env ? '更新变量成功' : '添加变量成功');
|
message.success(env ? '更新变量成功' : '新建变量成功');
|
||||||
} else {
|
} else {
|
||||||
message.error(data);
|
message.error(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const Initialization = () => {
|
|||||||
const submitAccountSetting = (values: any) => {
|
const submitAccountSetting = (values: any) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
request
|
request
|
||||||
.put(`${config.apiPrefix}init/user`, {
|
.put(`${config.apiPrefix}user/init`, {
|
||||||
data: {
|
data: {
|
||||||
username: values.username,
|
username: values.username,
|
||||||
password: values.password,
|
password: values.password,
|
||||||
@@ -52,8 +52,9 @@ const Initialization = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const submitNotification = (values: any) => {
|
const submitNotification = (values: any) => {
|
||||||
|
setLoading(true);
|
||||||
request
|
request
|
||||||
.put(`${config.apiPrefix}init/notification`, {
|
.put(`${config.apiPrefix}user/notification/init`, {
|
||||||
data: {
|
data: {
|
||||||
...values,
|
...values,
|
||||||
},
|
},
|
||||||
@@ -73,6 +74,10 @@ const Initialization = () => {
|
|||||||
setFields(_fields || []);
|
setFields(_fields || []);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.removeItem(config.authKey);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const steps = [
|
const steps = [
|
||||||
{
|
{
|
||||||
title: '欢迎使用',
|
title: '欢迎使用',
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const Login = () => {
|
|||||||
setTwoFactor(false);
|
setTwoFactor(false);
|
||||||
setWaitTime(null);
|
setWaitTime(null);
|
||||||
request
|
request
|
||||||
.post(`${config.apiPrefix}login`, {
|
.post(`${config.apiPrefix}user/login`, {
|
||||||
data: {
|
data: {
|
||||||
username: values.username,
|
username: values.username,
|
||||||
password: values.password,
|
password: values.password,
|
||||||
@@ -113,6 +113,14 @@ const Login = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const codeInputChange = (e: React.ChangeEvent) => {
|
||||||
|
const { value } = e.target as any;
|
||||||
|
const regx = /^[0-9]{6}$/;
|
||||||
|
if (regx.test(value)) {
|
||||||
|
completeTowFactor({ code: value });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isAuth = localStorage.getItem(config.authKey);
|
const isAuth = localStorage.getItem(config.authKey);
|
||||||
if (isAuth) {
|
if (isAuth) {
|
||||||
@@ -144,12 +152,15 @@ const Login = () => {
|
|||||||
{
|
{
|
||||||
pattern: /^[0-9]{6}$/,
|
pattern: /^[0-9]{6}$/,
|
||||||
message: '验证码为6位数字',
|
message: '验证码为6位数字',
|
||||||
validateTrigger: 'onBlur',
|
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
hasFeedback
|
|
||||||
>
|
>
|
||||||
<Input placeholder="6位数字" autoFocus autoComplete="off" />
|
<Input
|
||||||
|
placeholder="6位数字"
|
||||||
|
onChange={codeInputChange}
|
||||||
|
autoFocus
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ const EditModal = ({
|
|||||||
const [log, setLog] = useState<string>('');
|
const [log, setLog] = useState<string>('');
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
const editorRef = useRef<any>(null);
|
const editorRef = useRef<any>(null);
|
||||||
|
const [isRunning, setIsRunning] = useState(false);
|
||||||
|
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
handleCancel();
|
handleCancel();
|
||||||
@@ -80,7 +81,22 @@ const EditModal = ({
|
|||||||
path: cNode.parent || '',
|
path: cNode.parent || '',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((data) => {});
|
.then((data) => {
|
||||||
|
setIsRunning(true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const stop = () => {
|
||||||
|
request
|
||||||
|
.put(`${config.apiPrefix}scripts/stop`, {
|
||||||
|
data: {
|
||||||
|
filename: cNode.value,
|
||||||
|
path: cNode.parent || '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
setIsRunning(false);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -94,6 +110,13 @@ const EditModal = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_message === '执行结束') {
|
||||||
|
_message = '';
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsRunning(false);
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
if (log) {
|
if (log) {
|
||||||
_message = `\n${_message}`;
|
_message = `\n${_message}`;
|
||||||
}
|
}
|
||||||
@@ -135,8 +158,12 @@ const EditModal = ({
|
|||||||
<Option value="shell">shell</Option>
|
<Option value="shell">shell</Option>
|
||||||
<Option value="python">python</Option>
|
<Option value="python">python</Option>
|
||||||
</Select>
|
</Select>
|
||||||
<Button type="primary" style={{ marginRight: 8 }} onClick={run}>
|
<Button
|
||||||
运行
|
type="primary"
|
||||||
|
style={{ marginRight: 8 }}
|
||||||
|
onClick={isRunning ? stop : run}
|
||||||
|
>
|
||||||
|
{isRunning ? '停止' : '运行'}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -169,6 +196,7 @@ const EditModal = ({
|
|||||||
type="primary"
|
type="primary"
|
||||||
style={{ marginRight: 8 }}
|
style={{ marginRight: 8 }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
stop();
|
||||||
handleCancel();
|
handleCancel();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -181,7 +209,12 @@ const EditModal = ({
|
|||||||
onClose={cancel}
|
onClose={cancel}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
>
|
>
|
||||||
<SplitPane split="vertical" minSize={200} defaultSize="50%">
|
<SplitPane
|
||||||
|
split="vertical"
|
||||||
|
minSize={200}
|
||||||
|
defaultSize="50%"
|
||||||
|
style={{ height: 'calc(100vh - 55px)' }}
|
||||||
|
>
|
||||||
<Editor
|
<Editor
|
||||||
language={language}
|
language={language}
|
||||||
value={value}
|
value={value}
|
||||||
@@ -196,9 +229,7 @@ const EditModal = ({
|
|||||||
editorRef.current = editor;
|
editorRef.current = editor;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div>
|
<pre style={{ height: '100%', whiteSpace: 'break-spaces' }}>{log}</pre>
|
||||||
<pre>{log}</pre>
|
|
||||||
</div>
|
|
||||||
</SplitPane>
|
</SplitPane>
|
||||||
<SaveModal
|
<SaveModal
|
||||||
visible={saveModalVisible}
|
visible={saveModalVisible}
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ const Script = ({ headerStyle, isPhone, theme, socketMessage }: any) => {
|
|||||||
) : (
|
) : (
|
||||||
<Menu>
|
<Menu>
|
||||||
<Menu.Item key="add" icon={<PlusOutlined />} onClick={addFile}>
|
<Menu.Item key="add" icon={<PlusOutlined />} onClick={addFile}>
|
||||||
添加
|
新建
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key="edit"
|
key="edit"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const AppModal = ({
|
|||||||
data: payload,
|
data: payload,
|
||||||
});
|
});
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
message.success(app ? '更新应用成功' : '添加应用成功');
|
message.success(app ? '更新应用成功' : '新建应用成功');
|
||||||
} else {
|
} else {
|
||||||
message.error(data);
|
message.error(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ const Setting = ({
|
|||||||
tabActiveKey === 'app'
|
tabActiveKey === 'app'
|
||||||
? [
|
? [
|
||||||
<Button key="2" type="primary" onClick={() => addApp()}>
|
<Button key="2" type="primary" onClick={() => addApp()}>
|
||||||
添加应用
|
新建应用
|
||||||
</Button>,
|
</Button>,
|
||||||
]
|
]
|
||||||
: []
|
: []
|
||||||
|
|||||||
@@ -55,6 +55,14 @@ export default {
|
|||||||
name: '任务日志',
|
name: '任务日志',
|
||||||
value: 'logs',
|
value: 'logs',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: '依赖管理',
|
||||||
|
value: 'dependencies',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '系统信息',
|
||||||
|
value: 'system',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
scopesMap: {
|
scopesMap: {
|
||||||
crons: '定时任务',
|
crons: '定时任务',
|
||||||
|
|||||||
+3
-3
@@ -34,12 +34,12 @@ const errorHandler = function (error: any) {
|
|||||||
|
|
||||||
const _request = extend({ timeout: 60000, params: { t: time }, errorHandler });
|
const _request = extend({ timeout: 60000, params: { t: time }, errorHandler });
|
||||||
const apiWhiteList = [
|
const apiWhiteList = [
|
||||||
'/api/login',
|
'/api/user/login',
|
||||||
'/open/auth/token',
|
'/open/auth/token',
|
||||||
'/api/user/two-factor/login',
|
'/api/user/two-factor/login',
|
||||||
'/api/system',
|
'/api/system',
|
||||||
'/api/init/user',
|
'/api/user/init',
|
||||||
'/api/init/notification',
|
'/api/user/notification/init',
|
||||||
];
|
];
|
||||||
|
|
||||||
_request.interceptors.request.use((url, options) => {
|
_request.interceptors.request.use((url, options) => {
|
||||||
|
|||||||
+8
-5
@@ -1,6 +1,9 @@
|
|||||||
export const version = '2.10.12';
|
export const version = '2.10.13';
|
||||||
export const changeLogLink = 'https://t.me/jiao_long/232';
|
export const changeLogLink = 'https://t.me/jiao_long/233';
|
||||||
export const changeLog = `2.10.12 版本说明
|
export const changeLog = `2.10.13 版本说明
|
||||||
1. 修复logo样式
|
1. task 命令执行脚本支持任意参数,比如 task xxx.js a b c d
|
||||||
2. 修复暗黑模式无法访问
|
2. 应用权限增加依赖管理、系统信息
|
||||||
|
3. 调试脚本增加停止操作,优化交互
|
||||||
|
4. 定时任务任务名修改展示效果,感谢https://github.com/tinet-jutt
|
||||||
|
5. 其他bug修复
|
||||||
`;
|
`;
|
||||||
|
|||||||
+1
-7
@@ -27,13 +27,7 @@
|
|||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"noEmit": false
|
"noEmit": false
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src/**/*", ".umirc.ts", "typings.d.ts", "back/**/*"],
|
||||||
"src/**/*",
|
|
||||||
"config/**/*",
|
|
||||||
".umirc.ts",
|
|
||||||
"typings.d.ts",
|
|
||||||
"back/**/*"
|
|
||||||
],
|
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"lib",
|
"lib",
|
||||||
|
|||||||
Reference in New Issue
Block a user