import { Injectable, Inject, Logger } from '@nestjs/common'; import { RecoverByMnemonicCommand } from './recover-by-mnemonic.command'; import { UserAccountRepository, USER_ACCOUNT_REPOSITORY } from '@/domain/repositories/user-account.repository.interface'; import { AccountSequence } from '@/domain/value-objects'; import { TokenService } from '@/application/services/token.service'; import { EventPublisherService } from '@/infrastructure/kafka/event-publisher.service'; import { BlockchainClientService } from '@/infrastructure/external/blockchain/blockchain-client.service'; import { ApplicationError } from '@/shared/exceptions/domain.exception'; import { RecoverAccountResult } from '../index'; import { generateRandomAvatarSvg } from '@/shared/utils/random-identity.util'; @Injectable() export class RecoverByMnemonicHandler { private readonly logger = new Logger(RecoverByMnemonicHandler.name); constructor( @Inject(USER_ACCOUNT_REPOSITORY) private readonly userRepository: UserAccountRepository, private readonly tokenService: TokenService, private readonly eventPublisher: EventPublisherService, private readonly blockchainClient: BlockchainClientService, ) {} async execute(command: RecoverByMnemonicCommand): Promise { const accountSequence = AccountSequence.create(command.accountSequence); const account = await this.userRepository.findByAccountSequence(accountSequence); if (!account) throw new ApplicationError('账户序列号不存在'); if (!account.isActive) throw new ApplicationError('账户已冻结或注销'); // 调用 blockchain-service 验证助记词(blockchain-service 内部查询哈希并验证) this.logger.log(`Verifying mnemonic for account ${command.accountSequence}`); const verifyResult = await this.blockchainClient.verifyMnemonicByAccount({ accountSequence: command.accountSequence, mnemonic: command.mnemonic, }); if (!verifyResult.valid) { this.logger.warn(`Mnemonic verification failed for account ${command.accountSequence}: ${verifyResult.message}`); throw new ApplicationError(verifyResult.message || '助记词错误'); } this.logger.log(`Mnemonic verified successfully for account ${command.accountSequence}`); // 如果头像为空,重新生成一个 let avatarUrl = account.avatarUrl; this.logger.log(`Account ${command.accountSequence} avatarUrl from DB: ${avatarUrl ? `长度=${avatarUrl.length}` : 'null'}`); if (avatarUrl) { this.logger.log(`Account ${command.accountSequence} avatarUrl前50字符: ${avatarUrl.substring(0, 50)}`); } if (!avatarUrl) { this.logger.log(`Account ${command.accountSequence} has no avatar, generating new one`); avatarUrl = generateRandomAvatarSvg(); account.updateProfile({ avatarUrl }); } account.addDevice(command.newDeviceId, command.deviceName); account.recordLogin(); await this.userRepository.save(account); const tokens = await this.tokenService.generateTokenPair({ userId: account.userId.toString(), accountSequence: account.accountSequence.value, deviceId: command.newDeviceId, }); await this.eventPublisher.publishAll(account.domainEvents); account.clearDomainEvents(); const result = { userId: account.userId.toString(), accountSequence: account.accountSequence.value, nickname: account.nickname, avatarUrl, referralCode: account.referralCode.value, accessToken: tokens.accessToken, refreshToken: tokens.refreshToken, }; this.logger.log(`RecoverByMnemonic result - accountSequence: ${result.accountSequence}, nickname: ${result.nickname}`); this.logger.log(`RecoverByMnemonic result - avatarUrl: ${result.avatarUrl ? `长度=${result.avatarUrl.length}` : 'null'}`); return result; } }