mirror of
https://github.com/whyour/qinglong.git
synced 2025-05-22 22:36:06 +08:00
完善订阅接口
This commit is contained in:
parent
5a21247cbb
commit
5523d537dc
|
@ -28,7 +28,8 @@ export default (app: Router) => {
|
|||
celebrate({
|
||||
body: Joi.object({
|
||||
type: Joi.string().required(),
|
||||
schedule: Joi.string().required(),
|
||||
schedule: Joi.string().optional(),
|
||||
intervalSchedule: Joi.object().optional(),
|
||||
name: Joi.string().optional(),
|
||||
url: Joi.string().required(),
|
||||
whitelist: Joi.string().optional(),
|
||||
|
@ -38,8 +39,8 @@ export default (app: Router) => {
|
|||
status: Joi.number().optional(),
|
||||
pull_type: Joi.string().optional(),
|
||||
pull_option: Joi.object().optional(),
|
||||
schedule_type: Joi.number().optional(),
|
||||
alias: Joi.number().required(),
|
||||
schedule_type: Joi.string().required(),
|
||||
alias: Joi.string().required(),
|
||||
}),
|
||||
}),
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
|
@ -156,7 +157,8 @@ export default (app: Router) => {
|
|||
celebrate({
|
||||
body: Joi.object({
|
||||
type: Joi.string().required(),
|
||||
schedule: Joi.string().required(),
|
||||
schedule: Joi.string().optional(),
|
||||
intervalSchedule: Joi.object().optional(),
|
||||
name: Joi.string().optional(),
|
||||
url: Joi.string().required(),
|
||||
whitelist: Joi.string().optional(),
|
||||
|
@ -166,8 +168,8 @@ export default (app: Router) => {
|
|||
status: Joi.number().optional(),
|
||||
pull_type: Joi.string().optional(),
|
||||
pull_option: Joi.object().optional(),
|
||||
schedule_type: Joi.number().optional(),
|
||||
alias: Joi.number().required(),
|
||||
schedule_type: Joi.string().optional(),
|
||||
alias: Joi.string().required(),
|
||||
id: Joi.number().required(),
|
||||
}),
|
||||
}),
|
||||
|
@ -176,6 +178,7 @@ export default (app: Router) => {
|
|||
try {
|
||||
if (
|
||||
!req.body.schedule ||
|
||||
typeof req.body.schedule === 'object' ||
|
||||
cron_parser.parseExpression(req.body.schedule).hasNext()
|
||||
) {
|
||||
const subscriptionService = Container.get(SubscriptionService);
|
||||
|
|
|
@ -7,7 +7,8 @@ export class Subscription {
|
|||
name?: string;
|
||||
type?: 'public-repo' | 'private-repo' | 'file';
|
||||
schedule_type?: 'crontab' | 'interval';
|
||||
schedule?: string | SimpleIntervalSchedule;
|
||||
schedule?: string;
|
||||
intervalSchedule?: SimpleIntervalSchedule;
|
||||
url?: string;
|
||||
whitelist?: string;
|
||||
blacklist?: string;
|
||||
|
@ -22,6 +23,7 @@ export class Subscription {
|
|||
isDisabled?: 1 | 0;
|
||||
log_path?: string;
|
||||
alias: string;
|
||||
command?: string;
|
||||
|
||||
constructor(options: Subscription) {
|
||||
this.id = options.id;
|
||||
|
@ -41,6 +43,7 @@ export class Subscription {
|
|||
this.log_path = options.log_path;
|
||||
this.schedule_type = options.schedule_type;
|
||||
this.alias = options.alias;
|
||||
this.intervalSchedule = options.intervalSchedule;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +72,11 @@ export const SubscriptionModel = sequelize.define<SubscriptionInstance>(
|
|||
unique: 'compositeIndex',
|
||||
type: DataTypes.STRING,
|
||||
},
|
||||
intervalSchedule: {
|
||||
unique: 'compositeIndex',
|
||||
type: DataTypes.JSON,
|
||||
},
|
||||
type: DataTypes.STRING,
|
||||
whitelist: DataTypes.STRING,
|
||||
blacklist: DataTypes.STRING,
|
||||
status: DataTypes.NUMBER,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Service, Inject } from 'typedi';
|
||||
import winston from 'winston';
|
||||
import nodeSchedule from 'node-schedule';
|
||||
import { Crontab } from '../data/cron';
|
||||
import { exec } from 'child_process';
|
||||
import {
|
||||
ToadScheduler,
|
||||
|
@ -10,6 +9,13 @@ import {
|
|||
SimpleIntervalSchedule,
|
||||
} from 'toad-scheduler';
|
||||
|
||||
interface ScheduleTaskType {
|
||||
id: number;
|
||||
command: string;
|
||||
name?: string;
|
||||
schedule?: string;
|
||||
}
|
||||
|
||||
@Service()
|
||||
export default class ScheduleService {
|
||||
private scheduleStacks = new Map<string, nodeSchedule.Job>();
|
||||
|
@ -20,7 +26,12 @@ export default class ScheduleService {
|
|||
|
||||
constructor(@Inject('logger') private logger: winston.Logger) {}
|
||||
|
||||
async createCronTask({ id = 0, command, name, schedule = '' }: Crontab) {
|
||||
async createCronTask({
|
||||
id = 0,
|
||||
command,
|
||||
name,
|
||||
schedule = '',
|
||||
}: ScheduleTaskType) {
|
||||
const _id = this.formatId(id);
|
||||
this.logger.info(
|
||||
'[创建cron任务],任务ID: %s,cron: %s,任务名: %s,执行命令: %s',
|
||||
|
@ -32,7 +43,7 @@ export default class ScheduleService {
|
|||
|
||||
this.scheduleStacks.set(
|
||||
_id,
|
||||
nodeSchedule.scheduleJob(id + '', schedule, async () => {
|
||||
nodeSchedule.scheduleJob(_id, schedule, async () => {
|
||||
try {
|
||||
exec(
|
||||
command,
|
||||
|
@ -70,15 +81,16 @@ export default class ScheduleService {
|
|||
);
|
||||
}
|
||||
|
||||
async cancelCronTask({ id = 0, name }: Crontab) {
|
||||
async cancelCronTask({ id = 0, name }: ScheduleTaskType) {
|
||||
const _id = this.formatId(id);
|
||||
this.logger.info('[取消定时任务],任务名:%s', name);
|
||||
this.scheduleStacks.has(_id) && this.scheduleStacks.get(_id)?.cancel();
|
||||
}
|
||||
|
||||
async createIntervalTask(
|
||||
{ id = 0, command, name = '' }: Crontab,
|
||||
{ id = 0, command, name = '' }: ScheduleTaskType,
|
||||
schedule: SimpleIntervalSchedule,
|
||||
runImmediately = true,
|
||||
) {
|
||||
const _id = this.formatId(id);
|
||||
this.logger.info(
|
||||
|
@ -131,12 +143,12 @@ export default class ScheduleService {
|
|||
},
|
||||
);
|
||||
|
||||
const job = new LongIntervalJob({ ...schedule }, task, _id);
|
||||
const job = new LongIntervalJob({ ...schedule, runImmediately }, task, _id);
|
||||
|
||||
this.intervalSchedule.addIntervalJob(job);
|
||||
}
|
||||
|
||||
async cancelIntervalTask({ id = 0, name }: Crontab) {
|
||||
async cancelIntervalTask({ id = 0, name }: ScheduleTaskType) {
|
||||
const _id = this.formatId(id);
|
||||
this.logger.info('[取消interval任务],任务ID: %s,任务名:%s', _id, name);
|
||||
this.intervalSchedule.removeById(_id);
|
||||
|
|
|
@ -14,10 +14,15 @@ import { promises, existsSync } from 'fs';
|
|||
import { promisify } from 'util';
|
||||
import { Op } from 'sequelize';
|
||||
import path from 'path';
|
||||
import ScheduleService from './schedule';
|
||||
import { SimpleIntervalSchedule } from 'toad-scheduler';
|
||||
|
||||
@Service()
|
||||
export default class SubscriptionService {
|
||||
constructor(@Inject('logger') private logger: winston.Logger) {}
|
||||
constructor(
|
||||
@Inject('logger') private logger: winston.Logger,
|
||||
private scheduleService: ScheduleService,
|
||||
) {}
|
||||
|
||||
public async list(searchText?: string): Promise<Subscription[]> {
|
||||
let query = {};
|
||||
|
@ -75,9 +80,38 @@ export default class SubscriptionService {
|
|||
}
|
||||
}
|
||||
|
||||
private formatCommand(doc: Subscription) {
|
||||
let command = 'ql ';
|
||||
const { type, url, whitelist, blacklist, dependences, branch } = doc;
|
||||
if (type === 'file') {
|
||||
command += `raw ${url}`;
|
||||
} else {
|
||||
command += `repo ${url} ${whitelist || ''} ${blacklist || ''} ${
|
||||
dependences || ''
|
||||
} ${branch || ''}`;
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
private handleTask(doc: Subscription, needCreate = true) {
|
||||
doc.command = this.formatCommand(doc);
|
||||
if (doc.schedule_type === 'crontab') {
|
||||
this.scheduleService.cancelCronTask(doc as any);
|
||||
needCreate && this.scheduleService.createCronTask(doc as any);
|
||||
} else {
|
||||
this.scheduleService.cancelIntervalTask(doc as any);
|
||||
needCreate &&
|
||||
this.scheduleService.createIntervalTask(
|
||||
doc as any,
|
||||
doc.intervalSchedule as SimpleIntervalSchedule,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async create(payload: Subscription): Promise<Subscription> {
|
||||
const tab = new Subscription(payload);
|
||||
const doc = await this.insert(tab);
|
||||
this.handleTask(doc);
|
||||
return doc;
|
||||
}
|
||||
|
||||
|
@ -87,6 +121,7 @@ export default class SubscriptionService {
|
|||
|
||||
public async update(payload: Subscription): Promise<Subscription> {
|
||||
const newDoc = await this.updateDb(payload);
|
||||
this.handleTask(newDoc);
|
||||
return newDoc;
|
||||
}
|
||||
|
||||
|
@ -156,7 +191,9 @@ export default class SubscriptionService {
|
|||
this.logger.silly(error);
|
||||
}
|
||||
}
|
||||
const err = await this.killTask('');
|
||||
this.handleTask(doc, false);
|
||||
const command = this.formatCommand(doc);
|
||||
const err = await this.killTask(command);
|
||||
const absolutePath = path.resolve(config.logPath, `${doc.log_path}`);
|
||||
const logFileExist = doc.log_path && (await fileExist(absolutePath));
|
||||
if (logFileExist) {
|
||||
|
@ -219,17 +256,16 @@ export default class SubscriptionService {
|
|||
return;
|
||||
}
|
||||
|
||||
let { id, log_path } = cron;
|
||||
let { id, log_path, name } = cron;
|
||||
const command = this.formatCommand(cron);
|
||||
const absolutePath = path.resolve(config.logPath, `${log_path}`);
|
||||
const logFileExist = log_path && (await fileExist(absolutePath));
|
||||
|
||||
this.logger.silly('Running job');
|
||||
this.logger.silly('Running job' + name);
|
||||
this.logger.silly('ID: ' + id);
|
||||
this.logger.silly('Original command: ');
|
||||
this.logger.silly('Original command: ' + command);
|
||||
|
||||
let cmdStr = '';
|
||||
|
||||
const cp = spawn(cmdStr, { shell: '/bin/bash' });
|
||||
const cp = spawn(command, { shell: '/bin/bash' });
|
||||
|
||||
await SubscriptionModel.update(
|
||||
{ status: SubscriptionStatus.running, pid: cp.pid },
|
||||
|
@ -266,10 +302,18 @@ export default class SubscriptionService {
|
|||
}
|
||||
|
||||
public async disabled(ids: number[]) {
|
||||
const docs = await SubscriptionModel.findAll({ where: { id: ids } });
|
||||
for (const doc of docs) {
|
||||
this.handleTask(doc, false);
|
||||
}
|
||||
await SubscriptionModel.update({ isDisabled: 1 }, { where: { id: ids } });
|
||||
}
|
||||
|
||||
public async enabled(ids: number[]) {
|
||||
const docs = await SubscriptionModel.findAll({ where: { id: ids } });
|
||||
for (const doc of docs) {
|
||||
this.handleTask(doc);
|
||||
}
|
||||
await SubscriptionModel.update({ isDisabled: 0 }, { where: { id: ids } });
|
||||
}
|
||||
|
||||
|
|
|
@ -281,7 +281,7 @@ const SubscriptionModal = ({
|
|||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="schedule"
|
||||
name={scheduleType === 'crontab' ? 'schedule' : 'intervalSchedule'}
|
||||
label="定时规则"
|
||||
rules={[
|
||||
{ required: true },
|
||||
|
|
Loading…
Reference in New Issue
Block a user