import { Injectable, Logger, NotFoundException } from "@nestjs/common"; import { firstValueFrom } from "rxjs"; import { MailboxInfo } from "../../mail-server/interfaces/mailboxes-response.interface"; import { MailServerService } from "../../mail-server/services/mail-server.service"; import { MailboxEnum } from "../../mailbox/enums/mailbox.enum"; export interface UserMailboxIds { inbox: string; sent: string; drafts: string; trash: string; junk: string; archive: string; favorite: string; } @Injectable() export class MailboxResolverService { private readonly logger = new Logger(MailboxResolverService.name); private readonly mailboxCache = new Map(); private readonly cacheExpiry = new Map(); private readonly CACHE_DURATION = 5 * 60 * 1000; // 5 minutes constructor(private readonly mailServerService: MailServerService) {} /** * Get user mailbox IDs with caching */ async getUserMailboxIds(userId: string): Promise { const cached = this.getCachedMailboxIds(userId); if (cached) return cached; this.logger.log(`Fetching mailbox IDs for user: ${userId}`); try { const mailboxes = await firstValueFrom(this.mailServerService.mailboxes.listMailboxes(userId)); const mailboxIds: UserMailboxIds = { inbox: this.findMailboxId(mailboxes.results, MailboxEnum.INBOX), sent: this.findMailboxId(mailboxes.results, MailboxEnum.SENT), drafts: this.findMailboxId(mailboxes.results, MailboxEnum.DRAFTS), trash: this.findMailboxId(mailboxes.results, MailboxEnum.TRASH), junk: this.findMailboxId(mailboxes.results, MailboxEnum.Junk, false), archive: this.findMailboxId(mailboxes.results, MailboxEnum.ARCHIVE, false), favorite: this.findMailboxId(mailboxes.results, MailboxEnum.FAVORITE, false), }; this.cacheMailboxIds(userId, mailboxIds); this.logger.log(`Mailbox IDs cached for user: ${userId}`); return mailboxIds; } catch (error) { this.logger.error(`Failed to fetch mailbox IDs for user ${userId}: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } /** * Get specific mailbox ID */ async getMailboxId(userId: string, mailboxType: keyof UserMailboxIds): Promise { const mailboxIds = await this.getUserMailboxIds(userId); const mailboxId = mailboxIds[mailboxType]; if (!mailboxId) { throw new NotFoundException(`${mailboxType} mailbox not found for user ${userId}`); } return mailboxId; } /** * Get drafts mailbox ID */ async getDraftsMailboxId(userId: string): Promise { return this.getMailboxId(userId, "drafts"); } /** * Get inbox mailbox ID */ async getInboxMailboxId(userId: string): Promise { return this.getMailboxId(userId, "inbox"); } /** * Get sent mailbox ID */ async getSentMailboxId(userId: string): Promise { return this.getMailboxId(userId, "sent"); } /** * Get trash mailbox ID */ async getTrashMailboxId(userId: string): Promise { return this.getMailboxId(userId, "trash"); } async getJunkMailboxId(userId: string): Promise { return this.getMailboxId(userId, "junk"); } async getArchiveMailboxId(userId: string): Promise { return this.getMailboxId(userId, "archive"); } async getFavoriteMailboxId(userId: string): Promise { return this.getMailboxId(userId, "favorite"); } /** * Clear cache for a specific user */ clearUserCache(userId: string): void { this.mailboxCache.delete(userId); this.cacheExpiry.delete(userId); this.logger.log(`Cache cleared for user: ${userId}`); } /** * Clear all cache */ clearAllCache(): void { this.mailboxCache.clear(); this.cacheExpiry.clear(); this.logger.log("All mailbox cache cleared"); } /** * Get cached mailbox IDs if not expired */ private getCachedMailboxIds(userId: string): UserMailboxIds | null { const cached = this.mailboxCache.get(userId); const expiry = this.cacheExpiry.get(userId); if (cached && expiry && Date.now() < expiry) { this.logger.debug(`Using cached mailbox IDs for user: ${userId}`); return cached; } if (cached) { this.logger.debug(`Cache expired for user: ${userId}`); this.clearUserCache(userId); } return null; } /** * Cache mailbox IDs with expiry */ private cacheMailboxIds(userId: string, mailboxIds: UserMailboxIds): void { this.mailboxCache.set(userId, mailboxIds); this.cacheExpiry.set(userId, Date.now() + this.CACHE_DURATION); } /** * Find mailbox ID by name */ private findMailboxId(mailboxes: MailboxInfo[], mailboxName: string, required: boolean = true): string { const mailbox = mailboxes.find((mb) => mb.name === mailboxName || mb.path === mailboxName || mb.specialUse === mailboxName); if (!mailbox && required) { throw new NotFoundException(`${mailboxName} mailbox not found`); } return mailbox?.id || ""; } }