courrier multi account restore compose
This commit is contained in:
parent
5152f9ded0
commit
7fc8e83330
@ -30,94 +30,45 @@ export interface EmailListResult {
|
||||
mailboxes: string[];
|
||||
}
|
||||
|
||||
// Connection pool to reuse IMAP clients
|
||||
// Connection pool management
|
||||
const connectionPool: Record<string, { client: ImapFlow; lastUsed: number }> = {};
|
||||
const CONNECTION_TIMEOUT = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
// Clean up idle connections periodically
|
||||
setInterval(() => {
|
||||
const now = Date.now();
|
||||
|
||||
Object.entries(connectionPool).forEach(([key, { client, lastUsed }]) => {
|
||||
if (now - lastUsed > CONNECTION_TIMEOUT) {
|
||||
console.log(`Closing idle IMAP connection for ${key}`);
|
||||
client.logout().catch(err => {
|
||||
console.error(`Error closing connection for ${key}:`, err);
|
||||
});
|
||||
if (client && client.usable) {
|
||||
client.logout().catch(err => {
|
||||
console.error(`Error closing connection for ${key}:`, err);
|
||||
});
|
||||
}
|
||||
delete connectionPool[key];
|
||||
}
|
||||
});
|
||||
}, 60 * 1000); // Check every minute
|
||||
|
||||
/**
|
||||
* Get IMAP connection for a user, reusing existing connections when possible
|
||||
* Get IMAP connection for a user
|
||||
*/
|
||||
export async function getImapConnection(
|
||||
userId: string,
|
||||
accountId?: string
|
||||
): Promise<ImapFlow> {
|
||||
console.log(`Getting IMAP connection for user ${userId}${accountId ? ` account ${accountId}` : ''}`);
|
||||
export async function getImapConnection(userId: string, accountId?: string): Promise<ImapFlow> {
|
||||
const key = `${userId}:${accountId || 'default'}`;
|
||||
|
||||
// First try to get credentials from Redis cache
|
||||
let credentials = accountId
|
||||
? await getCachedEmailCredentials(userId, accountId)
|
||||
: await getCachedEmailCredentials(userId, 'default');
|
||||
// Check if we have a valid connection in the pool
|
||||
const existingConnection = connectionPool[key];
|
||||
if (existingConnection && existingConnection.client.usable) {
|
||||
existingConnection.lastUsed = Date.now();
|
||||
return existingConnection.client;
|
||||
}
|
||||
|
||||
// If not in cache, get from database and cache them
|
||||
// Get credentials from cache or database
|
||||
const credentials = await getCachedEmailCredentials(userId, accountId || 'default');
|
||||
if (!credentials) {
|
||||
console.log(`Credentials not found in cache for ${userId}${accountId ? ` account ${accountId}` : ''}, attempting database lookup`);
|
||||
credentials = await getUserEmailCredentials(userId, accountId);
|
||||
if (!credentials) {
|
||||
throw new Error('No email credentials found');
|
||||
}
|
||||
|
||||
// Cache credentials for future use
|
||||
await cacheEmailCredentials(userId, accountId || 'default', credentials);
|
||||
throw new Error('No email credentials found');
|
||||
}
|
||||
|
||||
// Validate credentials
|
||||
if (!credentials.password) {
|
||||
console.error(`Missing password in credentials for user ${userId}${accountId ? ` account ${accountId}` : ''}`);
|
||||
throw new Error('No password configured');
|
||||
}
|
||||
|
||||
if (!credentials.email || !credentials.host) {
|
||||
console.error(`Incomplete credentials for user ${userId}${accountId ? ` account ${accountId}` : ''}`);
|
||||
throw new Error('Invalid email credentials configuration');
|
||||
}
|
||||
|
||||
// Use accountId in connection key to ensure different accounts get different connections
|
||||
const connectionKey = `${userId}:${accountId || 'default'}`;
|
||||
const existingConnection = connectionPool[connectionKey];
|
||||
|
||||
// Try to get session data from Redis
|
||||
const sessionData = await getCachedImapSession(userId);
|
||||
|
||||
// Return existing connection if available and connected
|
||||
if (existingConnection) {
|
||||
try {
|
||||
if (existingConnection.client.usable) {
|
||||
existingConnection.lastUsed = Date.now();
|
||||
console.log(`Reusing existing IMAP connection for ${connectionKey}`);
|
||||
|
||||
// Update session data in Redis
|
||||
if (sessionData) {
|
||||
await cacheImapSession(userId, {
|
||||
...sessionData,
|
||||
lastActive: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
return existingConnection.client;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`Existing connection for ${connectionKey} is not usable, creating new connection`);
|
||||
// Will create a new connection below
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Creating new IMAP connection for ${connectionKey}`);
|
||||
|
||||
// Create new connection
|
||||
const client = new ImapFlow({
|
||||
host: credentials.host,
|
||||
@ -125,30 +76,18 @@ export async function getImapConnection(
|
||||
secure: true,
|
||||
auth: {
|
||||
user: credentials.email,
|
||||
pass: credentials.password,
|
||||
pass: credentials.password
|
||||
},
|
||||
logger: false,
|
||||
emitLogs: false,
|
||||
tls: {
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
logger: false
|
||||
});
|
||||
|
||||
try {
|
||||
await client.connect();
|
||||
console.log(`Successfully connected to IMAP server for ${connectionKey}`);
|
||||
|
||||
// Store in connection pool
|
||||
connectionPool[connectionKey] = {
|
||||
client,
|
||||
lastUsed: Date.now()
|
||||
};
|
||||
|
||||
connectionPool[key] = { client, lastUsed: Date.now() };
|
||||
return client;
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
console.error(`IMAP connection error for ${connectionKey}:`, errorMessage);
|
||||
throw new Error(`Failed to connect to IMAP server: ${errorMessage}`);
|
||||
} catch (error) {
|
||||
console.error('Error connecting to IMAP:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,7 +220,7 @@ export async function getEmails(
|
||||
|
||||
// Get IMAP connection
|
||||
client = await getImapConnection(userId, accountId);
|
||||
if (!client) {
|
||||
if (!client || !client.usable) {
|
||||
throw new Error('Failed to establish IMAP connection');
|
||||
}
|
||||
|
||||
@ -381,7 +320,7 @@ export async function getEmails(
|
||||
console.error('Error fetching emails:', error);
|
||||
throw error;
|
||||
} finally {
|
||||
if (client) {
|
||||
if (client && client.usable) {
|
||||
try {
|
||||
await client.mailboxClose();
|
||||
} catch (error) {
|
||||
@ -472,9 +411,10 @@ export async function getEmailContent(
|
||||
contentType: att.contentType,
|
||||
size: att.size || 0
|
||||
})),
|
||||
html: rawHtml,
|
||||
text: parsedEmail.text || undefined,
|
||||
content: rawHtml || parsedEmail.text || '',
|
||||
content: {
|
||||
text: parsedEmail.text || '',
|
||||
html: rawHtml || ''
|
||||
},
|
||||
folder,
|
||||
contentFetched: true,
|
||||
size: size || 0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user