diff --git a/app.js b/app.js index 309a80c..fc1207b 100644 --- a/app.js +++ b/app.js @@ -19,7 +19,24 @@ const clientNotification = new ClientNotification() debug('Client notification service initialized') clientNotification.use(io) -const imapService = new ImapService(config) +let inboxLock = null + // Initialize inbox locking if enabled +if (config.lock.enabled) { + inboxLock = new InboxLock(config.lock.dbPath) + app.set('inboxLock', inboxLock) + console.log(`Inbox locking enabled (auto-release after ${config.lock.releaseHours} hours)`) + + // Check for inactive locked inboxes + setInterval(() => { + const inactive = inboxLock.getInactive(config.lock.releaseHours) + if (inactive.length > 0) { + console.log(`Releasing ${inactive.length} inactive locked inbox(es)`) + inactive.forEach(address => inboxLock.release(address)) + } + }, config.imap.refreshIntervalSeconds * 1000) +} + +const imapService = new ImapService(config, inboxLock) debug('IMAP service initialized') const mailProcessingService = new MailProcessingService( new MailRepository(), @@ -58,22 +75,6 @@ imapService.on(ImapService.EVENT_ERROR, error => { app.set('mailProcessingService', mailProcessingService) app.set('config', config) -// Initialize inbox locking if enabled -if (config.lock.enabled) { - const inboxLock = new InboxLock(config.lock.dbPath) - app.set('inboxLock', inboxLock) - console.log(`Inbox locking enabled (auto-release after ${config.lock.releaseHours} hours)`) - - // Check for inactive locked inboxes - setInterval(() => { - const inactive = inboxLock.getInactive(config.lock.releaseHours) - if (inactive.length > 0) { - console.log(`Releasing ${inactive.length} inactive locked inbox(es)`) - inactive.forEach(address => inboxLock.release(address)) - } - }, config.imap.refreshIntervalSeconds * 1000) -} - app.locals.imapService = imapService app.locals.mailProcessingService = mailProcessingService @@ -104,4 +105,4 @@ server.on('error', error => { console.error('Fatal web server error', error) process.exit(1) } -}) +}) \ No newline at end of file diff --git a/application/imap-service.js b/application/imap-service.js index 40a60f8..9d9ec5b 100644 --- a/application/imap-service.js +++ b/application/imap-service.js @@ -89,13 +89,13 @@ imaps.ImapSimple.prototype.closeBox = function(autoExpunge = true, callback) { * With this abstraction it would be easy to replace this with any inbound mail service like mailgun.com. */ class ImapService extends EventEmitter { - constructor(config) { + constructor(config, inboxLock = null) { super() if (!config || !config.imap) { throw new Error("ImapService requires a valid config with 'imap' object"); } this.config = config - + this.inboxLock = inboxLock this.loadedUids = new Set() this.connection = null this.initialLoadDone = false @@ -255,15 +255,10 @@ class ImapService extends EventEmitter { // Get locked inboxes if available let lockedAddresses = []; - if (typeof this.config.lock !== 'undefined' && this.config.lock.enabled && this.config.lock.dbPath) { + if (this.inboxLock && typeof this.inboxLock.getAllLocked === 'function') { try { - // Try to get the app instance and inboxLock - const app = require('../app'); - const inboxLock = app.get('inboxLock'); - if (inboxLock && typeof inboxLock.getAllLocked === 'function') { - lockedAddresses = inboxLock.getAllLocked().map(addr => addr.toLowerCase()); - debug(`Locked inboxes (excluded from purge): ${lockedAddresses.join(', ')}`); - } + lockedAddresses = this.inboxLock.getAllLocked().map(addr => addr.toLowerCase()); + debug(`Locked inboxes (excluded from purge): ${lockedAddresses.length > 0 ? lockedAddresses.join(', ') : '0'}`); } catch (err) { debug('Could not get locked inboxes for purge:', err.message); } @@ -275,8 +270,7 @@ class ImapService extends EventEmitter { const date = mail.attributes.date; const uid = parseInt(mail.attributes.uid); const toAddresses = Array.isArray(mail.parts[0].body.to) ? - mail.parts[0].body.to.map(a => a.toLowerCase()) : - [String(mail.parts[0].body.to).toLowerCase()]; + mail.parts[0].body.to.map(a => a.toLowerCase()) : [String(mail.parts[0].body.to).toLowerCase()]; if (exampleUids.includes(uid)) return false; if (toAddresses.some(addr => lockedAddresses.includes(addr))) return false; diff --git a/application/mail-processing-service.js b/application/mail-processing-service.js index c909bea..3e0fe39 100644 --- a/application/mail-processing-service.js +++ b/application/mail-processing-service.js @@ -70,6 +70,7 @@ class MailProcessingService extends EventEmitter { } onNewMail(mail) { + debug('onNewMail called for:', mail.to) if (this.initialLoadDone) { // For now, only log messages if they arrive after the initial load debug('New mail for', mail.to[0]) @@ -79,7 +80,9 @@ class MailProcessingService extends EventEmitter { debug('Adding mail to repository for recipient:', to) this.mailRepository.add(to, mail) debug('Emitting notification for:', to) - return this.clientNotification.emit(to) + const emitResult = this.clientNotification.emit(to) + debug('clientNotification.emit result:', emitResult) + return emitResult }) } diff --git a/infrastructure/web/client-notification.js b/infrastructure/web/client-notification.js index 7fb2a15..10ce455 100644 --- a/infrastructure/web/client-notification.js +++ b/infrastructure/web/client-notification.js @@ -6,27 +6,28 @@ require('events').defaultMaxListeners = 50; * Receives sign-ins from users and notifies them when new mails are available. */ class ClientNotification extends EventEmitter { - use(io) { - io.on('connection', socket => { - socket.on('sign in', address => this._signIn(socket, address)) - }) - } + use(io) { + io.on('connection', socket => { + socket.on('sign in', address => this._signIn(socket, address)) + }) + } - _signIn(socket, address) { - debug(`socketio signed in: ${address}`) + _signIn(socket, address) { + debug(`socketio signed in: ${address}`) - const newMailListener = () => { - debug(`${address} has new messages, sending notification`) - socket.emit('new emails') - } + const newMailListener = () => { + debug(`${address} has new messages, sending notification`) + socket.emit('new emails') + debug(`socket.emit('new emails') sent to ${address}`) + } - this.on(address, newMailListener) + this.on(address, newMailListener) - socket.on('disconnect', reason => { - debug(`client disconnect: ${address} (${reason})`) - this.removeListener(address, newMailListener) - }) - } + socket.on('disconnect', reason => { + debug(`client disconnect: ${address} (${reason})`) + this.removeListener(address, newMailListener) + }) + } } -module.exports = ClientNotification +module.exports = ClientNotification \ No newline at end of file