feat(push): 新增设备推送和测试功能
- 新增基于设备令牌的推送通知接口 - 添加推送测试服务,支持应用启动时自动测试 - 新增推送测试文档说明 - 更新 APNS 配置和日志记录 - 迁移至 apns2 库的 PushType 枚举 - 替换订阅密钥文件 - 添加项目规则文档
This commit is contained in:
99
src/push-notifications/push-test.service.ts
Normal file
99
src/push-notifications/push-test.service.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { PushNotificationsService } from './push-notifications.service';
|
||||
import { PushTokenService } from './push-token.service';
|
||||
import { UserPushToken } from './models/user-push-token.model';
|
||||
import { InjectModel } from '@nestjs/sequelize';
|
||||
import { Op } from 'sequelize';
|
||||
import { PushType } from 'apns2';
|
||||
|
||||
@Injectable()
|
||||
export class PushTestService implements OnModuleInit {
|
||||
private readonly logger = new Logger(PushTestService.name);
|
||||
|
||||
constructor(
|
||||
@InjectModel(UserPushToken)
|
||||
private readonly pushTokenModel: typeof UserPushToken,
|
||||
private readonly pushNotificationsService: PushNotificationsService,
|
||||
private readonly pushTokenService: PushTokenService,
|
||||
private readonly configService: ConfigService,
|
||||
) { }
|
||||
|
||||
/**
|
||||
* 模块初始化时执行
|
||||
*/
|
||||
async onModuleInit() {
|
||||
// 检查是否启用推送测试
|
||||
const enablePushTest = this.configService.get<boolean>('ENABLE_PUSH_TEST', false);
|
||||
|
||||
if (!enablePushTest) {
|
||||
this.logger.log('Push test is disabled. Skipping...');
|
||||
return;
|
||||
}
|
||||
|
||||
// 延迟执行,确保应用完全启动
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await this.performPushTest();
|
||||
} catch (error) {
|
||||
this.logger.error(`Push test failed: ${error.message}`, error);
|
||||
}
|
||||
}, 5000); // 5秒后执行
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行推送测试
|
||||
*/
|
||||
private async performPushTest(): Promise<void> {
|
||||
this.logger.log('Starting push test...');
|
||||
|
||||
try {
|
||||
// 获取所有活跃的推送令牌
|
||||
const activeTokens = await this.pushTokenModel.findAll({
|
||||
where: {
|
||||
isActive: true,
|
||||
},
|
||||
limit: 10, // 限制测试数量,避免发送过多推送
|
||||
});
|
||||
|
||||
if (activeTokens.length === 0) {
|
||||
this.logger.log('No active push tokens found for testing');
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(`Found ${activeTokens.length} active tokens for testing`);
|
||||
|
||||
// 准备测试推送内容
|
||||
const testTitle = this.configService.get<string>('PUSH_TEST_TITLE', '测试推送');
|
||||
const testBody = this.configService.get<string>('PUSH_TEST_BODY', '这是一条测试推送消息,用于验证推送功能是否正常工作。');
|
||||
|
||||
// 发送测试推送
|
||||
const result = await this.pushNotificationsService.sendBatchNotificationToDevices({
|
||||
deviceTokens: activeTokens.map(token => token.deviceToken),
|
||||
title: testTitle,
|
||||
body: testBody,
|
||||
pushType: PushType.alert,
|
||||
});
|
||||
|
||||
if (result.code === 0) {
|
||||
this.logger.log(`Push test completed successfully. Sent: ${result.data.successCount}, Failed: ${result.data.failedCount}`);
|
||||
} else {
|
||||
this.logger.warn(`Push test completed with issues. Sent: ${result.data.successCount}, Failed: ${result.data.failedCount}`);
|
||||
}
|
||||
|
||||
// 记录详细结果
|
||||
if (result.data.results && result.data.results.length > 0) {
|
||||
result.data.results.forEach((resultItem, index) => {
|
||||
if (resultItem.success) {
|
||||
this.logger.log(`Push test success for user ${resultItem.userId}, device ${resultItem.deviceToken.substring(0, 10)}...`);
|
||||
} else {
|
||||
this.logger.warn(`Push test failed for user ${resultItem.userId}, device ${resultItem.deviceToken.substring(0, 10)}...: ${resultItem.error}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error(`Error during push test: ${error.message}`, error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user