/** * DomainManager实现类 */ import { Domain, CreateDomainData, UpdateDomainData, DnsRecordType } from '../models/Domain'; import { DomainManager } from '../interfaces/DomainManager'; import { DomainDAO } from '../interfaces/DomainDAO'; import { DomainManagerConfig, DomainQuery, QueryOptions } from '../interfaces/common'; import { ValidationError, NotFoundError, ConflictError, InitializationError } from '../exceptions/DomainModelError'; /** * DomainManager的具体实现,处理域名管理的业务逻辑 */ export class DomainManagerImpl implements DomainManager { /** * 构造函数 * @param dao 域名数据访问对象 */ constructor(private dao: DomainDAO) {} /** * 初始化DomainManager */ public async initialize(config: DomainManagerConfig): Promise { try { await this.dao.initialize(); } catch (error) { throw new InitializationError(`Failed to initialize DomainManager: ${error instanceof Error ? error.message : String(error)}`); } } /** * 关闭DomainManager */ public async close(): Promise { await this.dao.close(); } /** * 创建新域名记录 */ public async createDomain(domainData: CreateDomainData): Promise { // 验证域名数据 this.validateDomainData(domainData); // 检查域名是否已存在 const existingDomain = await this.dao.findByName(domainData.name); if (existingDomain) { throw new ConflictError(`Domain with name ${domainData.name} already exists`); } // 创建完整的Domain对象 const domain: Domain = { ...domainData, id: this.generateId(), enabled: domainData.enabled !== false, // 默认启用 createdAt: new Date(), updatedAt: new Date() }; // 创建域名 return this.dao.create(domain); } /** * 根据ID获取域名 */ public async getDomainById(id: string): Promise { if (!id) { throw new ValidationError('Domain ID is required'); } return this.dao.findById(id); } /** * 根据名称获取域名 */ public async getDomainByName(name: string): Promise { if (!name) { throw new ValidationError('Domain name is required'); } return this.dao.findByName(name); } /** * 查询域名列表 */ public async findDomains(query?: DomainQuery, options?: QueryOptions): Promise { // 构建查询条件 const searchQuery: any = query || {}; // 构建排序条件 const sortOption = options?.sort || { createdAt: -1 }; // 转换 SortOption 类型为 DomainDAO 期望的 Record 类型 const sort: Record = this.convertSortOption(sortOption); // 计算分页参数 const skip = options?.offset || 0; const limit = options?.limit; // 执行查询 return this.dao.find(searchQuery, skip, limit, sort, options?.projection); } /** * 更新域名信息 */ public async updateDomain(id: string, domainData: UpdateDomainData): Promise { if (!id) { throw new ValidationError('Domain ID is required'); } // 检查域名是否存在 const existingDomain = await this.dao.findById(id); if (!existingDomain) { throw new NotFoundError(`Domain with ID ${id} not found`); } // 如果更新域名名称,检查是否与其他域名冲突 if (domainData.name && domainData.name !== existingDomain.name) { const duplicateDomain = await this.dao.findByName(domainData.name); if (duplicateDomain && duplicateDomain.id !== id) { throw new ConflictError(`Domain with name ${domainData.name} already exists`); } } // 验证更新的数据 const mergedDomain = { ...existingDomain, ...domainData, updatedAt: new Date() }; this.validateDomainData(mergedDomain); // 更新域名 const updatedDomain = await this.dao.update(id, domainData); if (!updatedDomain) { throw new NotFoundError(`Domain with ID ${id} not found`); } return updatedDomain; } /** * 删除域名 */ public async deleteDomain(id: string): Promise { if (!id) { throw new ValidationError('Domain ID is required'); } // 检查域名是否存在 const existingDomain = await this.dao.findById(id); if (!existingDomain) { return false; } // 删除域名 return this.dao.delete(id); } /** * 切换域名启用状态 */ public async toggleDomainStatus(id: string, enabled: boolean): Promise { if (!id) { throw new ValidationError('Domain ID is required'); } // 检查域名是否存在 const existingDomain = await this.dao.findById(id); if (!existingDomain) { throw new NotFoundError(`Domain with ID ${id} not found`); } // 更新域名状态 const updatedDomain = await this.dao.update(id, { enabled, updatedAt: new Date() }); if (!updatedDomain) { throw new NotFoundError(`Domain with ID ${id} not found`); } return updatedDomain; } /** * 验证域名数据 */ private validateDomainData(domain: CreateDomainData | UpdateDomainData | Domain): void { // 验证域名名称 if ('name' in domain && domain.name) { if (domain.name.trim() === '') { throw new ValidationError('Domain name is required'); } else if (!this.isValidDomainName(domain.name)) { throw new ValidationError(`Invalid domain name: ${domain.name}`, 'name'); } } // 验证记录类型 if ('recordType' in domain && domain.recordType) { if (!Object.values(DnsRecordType).includes(domain.recordType)) { throw new ValidationError(`Invalid record type: ${domain.recordType}`, 'recordType'); } } // 验证管理员 if ('admin' in domain && domain.admin) { if (domain.admin.trim() === '') { throw new ValidationError('Admin is required', 'admin'); } } // 验证TTL if ('ttl' in domain && domain.ttl !== undefined) { if (domain.ttl <= 0) { throw new ValidationError('TTL must be greater than 0', 'ttl'); } } // 验证优先级(仅MX记录) if ('priority' in domain && domain.priority !== undefined && domain.priority !== null) { if (domain.priority < 0) { throw new ValidationError('Priority must be a non-negative integer', 'priority'); } } } /** * 验证域名格式 */ private isValidDomainName(name: string): boolean { // 简单的域名格式验证 const domainRegex = /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/; return domainRegex.test(name); } /** * 生成唯一ID */ private generateId(): string { // 简单的ID生成逻辑,实际项目中应使用更可靠的方式 return Date.now().toString(36) + Math.random().toString(36).substr(2); } /** * 转换SortOption类型为Record类型 * @param sortOption SortOption类型的排序条件 * @returns Record类型的排序条件 */ private convertSortOption(sortOption: any): Record { const result: Record = {}; for (const [key, value] of Object.entries(sortOption)) { if (value === 'asc' || value === 1) { result[key] = 1; } else if (value === 'desc' || value === -1) { result[key] = -1; } else if (typeof value === 'number') { // 如果已经是数字类型,直接使用 result[key] = value > 0 ? 1 : -1; } } return result; } }