268 lines
7.1 KiB
JavaScript
268 lines
7.1 KiB
JavaScript
|
|
#!/usr/bin/env node
|
|||
|
|
|
|||
|
|
const fs = require('fs');
|
|||
|
|
const path = require('path');
|
|||
|
|
const BaseGenerator = require('./base-generator');
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* ⚡ 任务生成器
|
|||
|
|
* 专门负责生成NestJS任务/队列文件
|
|||
|
|
*/
|
|||
|
|
class JobGenerator extends BaseGenerator {
|
|||
|
|
constructor() {
|
|||
|
|
super('JobGenerator');
|
|||
|
|
this.config = {
|
|||
|
|
phpBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/niucloud-php/niucloud',
|
|||
|
|
nestjsBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest/src/core',
|
|||
|
|
discoveryResultPath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/tools/php-discovery-result.json'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
this.discoveryData = null;
|
|||
|
|
this.jobStats = {
|
|||
|
|
jobsCreated: 0,
|
|||
|
|
jobsSkipped: 0
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 运行任务生成
|
|||
|
|
*/
|
|||
|
|
async run() {
|
|||
|
|
try {
|
|||
|
|
console.log('⚡ 启动任务生成器...');
|
|||
|
|
console.log('目标:生成NestJS任务/队列文件\n');
|
|||
|
|
|
|||
|
|
// 加载PHP文件发现结果
|
|||
|
|
await this.loadDiscoveryData();
|
|||
|
|
|
|||
|
|
// 生成任务
|
|||
|
|
await this.generateJobs();
|
|||
|
|
|
|||
|
|
// 输出统计报告
|
|||
|
|
this.printStats();
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('❌ 任务生成失败:', error);
|
|||
|
|
this.stats.errors++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 加载PHP文件发现结果
|
|||
|
|
*/
|
|||
|
|
async loadDiscoveryData() {
|
|||
|
|
try {
|
|||
|
|
const data = fs.readFileSync(this.config.discoveryResultPath, 'utf8');
|
|||
|
|
this.discoveryData = JSON.parse(data);
|
|||
|
|
console.log(' ✅ 成功加载PHP文件发现结果');
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('❌ 加载发现结果失败:', error);
|
|||
|
|
throw error;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 生成任务
|
|||
|
|
*/
|
|||
|
|
async generateJobs() {
|
|||
|
|
console.log(' 🔨 生成任务...');
|
|||
|
|
|
|||
|
|
// 检查是否有任务数据
|
|||
|
|
if (!this.discoveryData.jobs || Object.keys(this.discoveryData.jobs).length === 0) {
|
|||
|
|
console.log(' ⚠️ 未发现PHP任务,跳过生成');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (const [moduleName, jobs] of Object.entries(this.discoveryData.jobs)) {
|
|||
|
|
// 检查PHP项目是否有对应的任务目录
|
|||
|
|
if (!this.hasPHPJobs(moduleName)) {
|
|||
|
|
console.log(` ⚠️ 模块 ${moduleName} 在PHP项目中无任务,跳过`);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (const [jobName, jobInfo] of Object.entries(jobs)) {
|
|||
|
|
await this.createJob(moduleName, jobName, jobInfo);
|
|||
|
|
this.stats.jobsCreated++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log(` ✅ 生成了 ${this.stats.jobsCreated} 个任务`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 创建任务
|
|||
|
|
*/
|
|||
|
|
async createJob(moduleName, jobName, jobInfo) {
|
|||
|
|
const jobDir = path.join(this.config.nestjsBasePath, moduleName, 'jobs');
|
|||
|
|
this.ensureDir(jobDir);
|
|||
|
|
|
|||
|
|
const normalizedBase = jobName.replace(/Job$/i, '');
|
|||
|
|
const jobPath = path.join(
|
|||
|
|
jobDir,
|
|||
|
|
`${this.toPascalCase(normalizedBase)}Job.ts`
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 检查是否有对应的PHP任务文件
|
|||
|
|
const phpJobPath = path.join(this.config.phpBasePath, 'app/job', moduleName, `${jobName}.php`);
|
|||
|
|
if (!fs.existsSync(phpJobPath)) {
|
|||
|
|
console.log(` ❌ 未找到PHP任务文件,跳过生成: ${phpJobPath}`);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const content = this.generateJobContent(moduleName, jobName);
|
|||
|
|
this.writeFile(jobPath, content, `Job for ${moduleName}/${jobName}`);
|
|||
|
|
this.jobStats.jobsCreated++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 生成任务内容
|
|||
|
|
*/
|
|||
|
|
generateJobContent(moduleName, jobName) {
|
|||
|
|
const baseName = jobName.replace(/Job$/i, '');
|
|||
|
|
const className = `${this.toPascalCase(baseName)}Job`;
|
|||
|
|
|
|||
|
|
return `import { Injectable, Logger } from '@nestjs/common';
|
|||
|
|
import { InjectQueue } from '@nestjs/bullmq';
|
|||
|
|
import { Queue } from 'bullmq';
|
|||
|
|
import { BusinessException } from '@wwjCommon/exceptions/business.exception';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* ${className} - 基于NestJS BullMQ
|
|||
|
|
* 参考: https://docs.nestjs.com/techniques/queues
|
|||
|
|
* 对应 Java: @Async + RabbitMQ
|
|||
|
|
* 对应 PHP: think\queue
|
|||
|
|
*/
|
|||
|
|
@Injectable()
|
|||
|
|
export class ${className} {
|
|||
|
|
private readonly logger = new Logger(${className}.name);
|
|||
|
|
|
|||
|
|
constructor(
|
|||
|
|
@InjectQueue('${moduleName}') private readonly queue: Queue
|
|||
|
|
) {}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 添加任务到队列 - 使用BullMQ标准API
|
|||
|
|
* 参考: https://docs.nestjs.com/techniques/queues#producers
|
|||
|
|
*/
|
|||
|
|
async addJob(data: any, options?: any) {
|
|||
|
|
try {
|
|||
|
|
const job = await this.queue.add('${baseName}', data, options);
|
|||
|
|
this.logger.log(\`${baseName} job added to queue: \${job.id}\`, data);
|
|||
|
|
return job;
|
|||
|
|
} catch (error) {
|
|||
|
|
this.logger.error('Failed to add ${baseName} job to queue:', error);
|
|||
|
|
throw new BusinessException('${baseName}任务添加失败');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理队列任务
|
|||
|
|
* 使用Core层基础设施:统一队列服务、异常处理、日志服务
|
|||
|
|
*/
|
|||
|
|
async processJob(data: any) {
|
|||
|
|
this.logger.log('${baseName} job processing:', data);
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 任务逻辑
|
|||
|
|
await this.executeJob(data);
|
|||
|
|
this.logger.log('${baseName} job completed successfully');
|
|||
|
|
} catch (error) {
|
|||
|
|
this.logger.error('${baseName} job failed:', error);
|
|||
|
|
// 使用Core层异常处理
|
|||
|
|
throw new BusinessException('${baseName}任务处理失败', error);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 执行任务
|
|||
|
|
* 使用Core层基础设施:日志服务、异常处理
|
|||
|
|
*/
|
|||
|
|
private async executeJob(data: any) {
|
|||
|
|
// 实现具体的任务逻辑
|
|||
|
|
// 例如:
|
|||
|
|
// - 数据清理
|
|||
|
|
// - 报表生成
|
|||
|
|
// - 邮件发送
|
|||
|
|
// - 数据同步
|
|||
|
|
// - 备份操作
|
|||
|
|
|
|||
|
|
this.logger.log('Executing ${baseName} job logic with data:', data);
|
|||
|
|
|
|||
|
|
// 模拟异步操作
|
|||
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|||
|
|
|
|||
|
|
this.logger.log('${baseName} job logic completed');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 手动触发任务
|
|||
|
|
* 使用Core层基础设施:日志服务、异常处理
|
|||
|
|
*/
|
|||
|
|
async triggerJob(data?: any) {
|
|||
|
|
this.logger.log('Manually triggering ${baseName} job...');
|
|||
|
|
try {
|
|||
|
|
await this.executeJob(data || {});
|
|||
|
|
} catch (error) {
|
|||
|
|
this.logger.error('Failed to trigger ${baseName} job:', error);
|
|||
|
|
// 使用Core层异常处理
|
|||
|
|
throw new BusinessException('${baseName}任务触发失败', error);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}`;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 转换为PascalCase
|
|||
|
|
*/
|
|||
|
|
toPascalCase(str) {
|
|||
|
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 转换为camelCase
|
|||
|
|
*/
|
|||
|
|
toCamelCase(str) {
|
|||
|
|
return str.charAt(0).toLowerCase() + str.slice(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
toPascalCase(str) {
|
|||
|
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 检查模块是否有PHP任务
|
|||
|
|
*/
|
|||
|
|
hasPHPJobs(moduleName) {
|
|||
|
|
const phpProjectPath = path.join(__dirname, '../../niucloud-php/niucloud');
|
|||
|
|
const jobPath = path.join(phpProjectPath, 'app/job', moduleName);
|
|||
|
|
return fs.existsSync(jobPath);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 确保目录存在
|
|||
|
|
*/
|
|||
|
|
ensureDir(dirPath) {
|
|||
|
|
if (!fs.existsSync(dirPath)) {
|
|||
|
|
fs.mkdirSync(dirPath, { recursive: true });
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 输出统计报告
|
|||
|
|
*/
|
|||
|
|
printStats() {
|
|||
|
|
super.printStats({
|
|||
|
|
'Jobs Created': this.jobStats.jobsCreated,
|
|||
|
|
'Jobs Skipped': this.jobStats.jobsSkipped
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果直接运行此文件
|
|||
|
|
if (require.main === module) {
|
|||
|
|
const generator = new JobGenerator();
|
|||
|
|
generator.run().catch(console.error);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = JobGenerator;
|