订阅增加before/after

This commit is contained in:
whyour 2022-05-20 01:15:45 +08:00
parent bdecdce118
commit 189826c5db
6 changed files with 112 additions and 18 deletions

View File

@ -38,6 +38,9 @@ export default (app: Router) => {
dependences: Joi.string().optional().allow('').allow(null), dependences: Joi.string().optional().allow('').allow(null),
pull_type: Joi.string().optional().allow('').allow(null), pull_type: Joi.string().optional().allow('').allow(null),
pull_option: Joi.object().optional().allow('').allow(null), pull_option: Joi.object().optional().allow('').allow(null),
extensions: Joi.string().optional().allow('').allow(null),
sub_before: Joi.string().optional().allow('').allow(null),
sub_after: Joi.string().optional().allow('').allow(null),
schedule_type: Joi.string().required(), schedule_type: Joi.string().required(),
alias: Joi.string().required(), alias: Joi.string().required(),
}), }),
@ -167,6 +170,9 @@ export default (app: Router) => {
pull_type: Joi.string().optional().allow('').allow(null), pull_type: Joi.string().optional().allow('').allow(null),
pull_option: Joi.object().optional().allow('').allow(null), pull_option: Joi.object().optional().allow('').allow(null),
schedule_type: Joi.string().optional().allow('').allow(null), schedule_type: Joi.string().optional().allow('').allow(null),
extensions: Joi.string().optional().allow('').allow(null),
sub_before: Joi.string().optional().allow('').allow(null),
sub_after: Joi.string().optional().allow('').allow(null),
alias: Joi.string().required(), alias: Joi.string().required(),
id: Joi.number().required(), id: Joi.number().required(),
}), }),

View File

@ -25,6 +25,9 @@ export class Subscription {
log_path?: string; log_path?: string;
alias: string; alias: string;
command?: string; command?: string;
extensions?: string;
sub_before?: string;
sub_after?: string;
constructor(options: Subscription) { constructor(options: Subscription) {
this.id = options.id; this.id = options.id;
@ -48,6 +51,9 @@ export class Subscription {
this.schedule_type = options.schedule_type; this.schedule_type = options.schedule_type;
this.alias = options.alias; this.alias = options.alias;
this.interval_schedule = options.interval_schedule; this.interval_schedule = options.interval_schedule;
this.extensions = options.extensions;
this.sub_before = options.sub_before;
this.sub_after = options.sub_after;
} }
} }
@ -85,6 +91,9 @@ export const SubscriptionModel = sequelize.define<SubscriptionInstance>(
blacklist: DataTypes.STRING, blacklist: DataTypes.STRING,
status: DataTypes.NUMBER, status: DataTypes.NUMBER,
dependences: DataTypes.STRING, dependences: DataTypes.STRING,
extensions: DataTypes.STRING,
sub_before: DataTypes.STRING,
sub_after: DataTypes.STRING,
branch: DataTypes.STRING, branch: DataTypes.STRING,
pull_type: DataTypes.STRING, pull_type: DataTypes.STRING,
pull_option: DataTypes.JSON, pull_option: DataTypes.JSON,

View File

@ -21,14 +21,16 @@ export interface TaskCallbacks {
onStart?: ( onStart?: (
cp: ChildProcessWithoutNullStreams, cp: ChildProcessWithoutNullStreams,
startTime: dayjs.Dayjs, startTime: dayjs.Dayjs,
) => void; ) => Promise<void>;
onEnd?: ( onEnd?: (
cp: ChildProcessWithoutNullStreams, cp: ChildProcessWithoutNullStreams,
endTime: dayjs.Dayjs, endTime: dayjs.Dayjs,
diff: number, diff: number,
) => void; ) => Promise<void>;
onLog?: (message: string) => void; onLog?: (message: string) => Promise<void>;
onError?: (message: string) => void; onError?: (message: string) => Promise<void>;
onBefore?: () => Promise<void>;
onAfter?: () => Promise<void>;
} }
@Service() @Service()
@ -44,33 +46,34 @@ export default class ScheduleService {
async runTask(command: string, callbacks: TaskCallbacks = {}) { async runTask(command: string, callbacks: TaskCallbacks = {}) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
await callbacks.onBefore?.();
const startTime = dayjs(); const startTime = dayjs();
const cp = spawn(command, { shell: '/bin/bash' }); const cp = spawn(command, { shell: '/bin/bash' });
callbacks.onStart?.(cp, startTime); await callbacks.onStart?.(cp, startTime);
cp.stdout.on('data', (data) => { cp.stdout.on('data', async (data) => {
callbacks.onLog?.(data.toString()); await callbacks.onLog?.(data.toString());
}); });
cp.stderr.on('data', (data) => { cp.stderr.on('data', async (data) => {
this.logger.error( this.logger.error(
'执行任务 %s 失败,时间:%s, 错误信息:%j', '执行任务 %s 失败,时间:%s, 错误信息:%j',
command, command,
new Date().toLocaleString(), new Date().toLocaleString(),
data.toString(), data.toString(),
); );
callbacks.onError?.(data.toString()); await callbacks.onError?.(data.toString());
}); });
cp.on('error', (err) => { cp.on('error', async (err) => {
this.logger.error( this.logger.error(
'创建任务 %s 失败,时间:%s, 错误信息:%j', '创建任务 %s 失败,时间:%s, 错误信息:%j',
command, command,
new Date().toLocaleString(), new Date().toLocaleString(),
err, err,
); );
callbacks.onError?.(JSON.stringify(err)); await callbacks.onError?.(JSON.stringify(err));
}); });
cp.on('exit', async (code, signal) => { cp.on('exit', async (code, signal) => {
@ -82,7 +85,12 @@ export default class ScheduleService {
cp.on('close', async (code) => { cp.on('close', async (code) => {
const endTime = dayjs(); const endTime = dayjs();
this.logger.info(`${command} pid: ${cp.pid} closed ${code}`); this.logger.info(`${command} pid: ${cp.pid} closed ${code}`);
callbacks.onEnd?.(cp, endTime, endTime.diff(startTime, 'seconds')); await callbacks.onEnd?.(
cp,
endTime,
endTime.diff(startTime, 'seconds'),
);
await callbacks.onAfter?.();
resolve(null); resolve(null);
}); });
} catch (error) { } catch (error) {
@ -92,7 +100,7 @@ export default class ScheduleService {
new Date().toLocaleString(), new Date().toLocaleString(),
error, error,
); );
callbacks.onError?.(JSON.stringify(error)); await callbacks.onError?.(JSON.stringify(error));
resolve(null); resolve(null);
} }
}); });

View File

@ -97,13 +97,13 @@ export default class SubscriptionService {
private formatCommand(doc: Subscription, url?: string) { private formatCommand(doc: Subscription, url?: string) {
let command = 'ql '; let command = 'ql ';
let _url = url || this.formatUrl(doc).url; let _url = url || this.formatUrl(doc).url;
const { type, whitelist, blacklist, dependences, branch } = doc; const { type, whitelist, blacklist, dependences, branch, extensions } = doc;
if (type === 'file') { if (type === 'file') {
command += `raw "${_url}"`; command += `raw "${_url}"`;
} else { } else {
command += `repo "${_url}" "${whitelist || ''}" "${blacklist || ''}" "${ command += `repo "${_url}" "${whitelist || ''}" "${blacklist || ''}" "${
dependences || '' dependences || ''
}" "${branch || ''}"`; }" "${branch || ''}" "${extensions || ''}"`;
} }
return command; return command;
} }
@ -219,6 +219,40 @@ export default class SubscriptionService {
const absolutePath = await this.handleLogPath(sub.log_path as string); const absolutePath = await this.handleLogPath(sub.log_path as string);
fs.appendFileSync(absolutePath, `\n${message}`); fs.appendFileSync(absolutePath, `\n${message}`);
}, },
onBefore: async () => {
return new Promise((resolve, reject) => {
if (doc.sub_before) {
exec(doc.sub_before, async (err, stdout, stderr) => {
const absolutePath = await this.handleLogPath(
doc.log_path as string,
);
fs.appendFileSync(
absolutePath,
stdout || stderr || `${JSON.stringify(err || {})}`,
);
});
} else {
resolve();
}
});
},
onAfter: async () => {
return new Promise((resolve, reject) => {
if (doc.sub_after) {
exec(doc.sub_after, async (err, stdout, stderr) => {
const absolutePath = await this.handleLogPath(
doc.log_path as string,
);
fs.appendFileSync(
absolutePath,
stdout || stderr || `${JSON.stringify(err || {})}`,
);
});
} else {
resolve();
}
});
},
}; };
} }

View File

@ -141,6 +141,7 @@ update_repo() {
local blackword="$3" local blackword="$3"
local dependence="$4" local dependence="$4"
local branch="$5" local branch="$5"
local extensions="$6"
local tmp="${url%/*}" local tmp="${url%/*}"
local authorTmp1="${tmp##*/}" local authorTmp1="${tmp##*/}"
local authorTmp2="${authorTmp1##*:}" local authorTmp2="${authorTmp1##*:}"
@ -159,7 +160,7 @@ update_repo() {
fi fi
if [[ $exit_status -eq 0 ]]; then if [[ $exit_status -eq 0 ]]; then
echo -e "\n更新${repo_path}成功...\n" echo -e "\n更新${repo_path}成功...\n"
diff_scripts "$repo_path" "$author" "$path" "$blackword" "$dependence" diff_scripts "$repo_path" "$author" "$path" "$blackword" "$dependence" "$extensions"
else else
echo -e "\n更新${repo_path}失败,请检查网络...\n" echo -e "\n更新${repo_path}失败,请检查网络...\n"
fi fi
@ -341,8 +342,9 @@ diff_scripts() {
local path="$3" local path="$3"
local blackword="$4" local blackword="$4"
local dependence="$5" local dependence="$5"
local extensions="$6"
gen_list_repo "$repo_path" "$author" "$path" "$blackword" "$dependence" gen_list_repo "$repo_path" "$author" "$path" "$blackword" "$dependence" "$extensions"
local list_add="$dir_list_tmp/${uniq_path}_add.list" local list_add="$dir_list_tmp/${uniq_path}_add.list"
local list_drop="$dir_list_tmp/${uniq_path}_drop.list" local list_drop="$dir_list_tmp/${uniq_path}_drop.list"
@ -378,6 +380,9 @@ gen_list_repo() {
local cmd="find ." local cmd="find ."
local index=0 local index=0
if [[ $6 ]]; then
file_extensions="$6"
fi
for extension in $file_extensions; do for extension in $file_extensions; do
if [[ $index -eq 0 ]]; then if [[ $index -eq 0 ]]; then
cmd="${cmd} -name \"*.${extension}\"" cmd="${cmd} -name \"*.${extension}\""
@ -458,6 +463,7 @@ main() {
local p4=$4 local p4=$4
local p5=$5 local p5=$5
local p6=$6 local p6=$6
local p7=$7
local log_time=$(date "+%Y-%m-%d-%H-%M-%S") local log_time=$(date "+%Y-%m-%d-%H-%M-%S")
local log_path="$dir_log/update/${log_time}_$p1.log" local log_path="$dir_log/update/${log_time}_$p1.log"
local begin_time=$(date '+%Y-%m-%d %H:%M:%S') local begin_time=$(date '+%Y-%m-%d %H:%M:%S')
@ -479,7 +485,7 @@ main() {
get_user_info get_user_info
get_uniq_path "$p2" "$p6" get_uniq_path "$p2" "$p6"
if [[ -n $p2 ]]; then if [[ -n $p2 ]]; then
update_repo "$p2" "$p3" "$p4" "$p5" "$p6" update_repo "$p2" "$p3" "$p4" "$p5" "$p6" "$p7"
else else
echo -e "命令输入错误...\n" echo -e "命令输入错误...\n"
usage usage

View File

@ -357,6 +357,37 @@ const SubscriptionModal = ({
placeholder="请输入脚本依赖文件关键词,多个关键词竖线分割" placeholder="请输入脚本依赖文件关键词,多个关键词竖线分割"
/> />
</Form.Item> </Form.Item>
<Form.Item
name="extensions"
label="文件后缀"
normalize={(value) => value.trim()}
tooltip="仓库需要拉取的文件后缀,多个后缀空格分隔"
>
<Input placeholder="请输入文件后缀" />
</Form.Item>
<Form.Item
name="sub_before"
label="sub_before"
normalize={(value) => value.trim()}
tooltip="仓库需要拉取的文件后缀,多个后缀空格分隔"
>
<Input.TextArea
rows={4}
autoSize={true}
placeholder="请输入拉取仓库前要执行的命令"
/>
</Form.Item>
<Form.Item
name="sub_after"
label="sub_after"
normalize={(value) => value.trim()}
>
<Input.TextArea
rows={4}
autoSize={true}
placeholder="请输入拉取仓库后要执行的命令"
/>
</Form.Item>
</> </>
)} )}
</Form> </Form>