Skip to content

Commit a15771c

Browse files
committed
Final cleanup for keywords functionality
1 parent dba06a5 commit a15771c

7 files changed

Lines changed: 100 additions & 97 deletions

File tree

lib/api/messages.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2833,7 +2833,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
28332833
.concat('unseen' in result.value ? (result.value.unseen ? [] : '\\Seen') : [])
28342834
.concat('flagged' in result.value ? (result.value.flagged ? '\\Flagged' : []) : [])
28352835
.concat('draft' in result.value ? (result.value.draft ? '\\Draft' : []) : [])
2836-
.concat(result.value.keywords || []),
2836+
.concat(result.value.keywords ?? []),
28372837
raw,
28382838
referencedMessage: referencedMessage || false
28392839
});

lib/api/updates.js

Lines changed: 82 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -451,75 +451,78 @@ function loadJournalStream(db, res, user, lastEventId, done, onEntry) {
451451
let changedKeywords = new Set();
452452
let flaggedChanged = false;
453453

454-
let emitFlaggedCounter = next => {
454+
let emitFlaggedCounter = async next => {
455455
if (!flaggedChanged) {
456456
return next();
457457
}
458458

459-
Promise.all([tools.getFlaggedCounter(db, user), tools.getFlaggedCounter(db, user, 'unseen')])
460-
.then(([total, unseen]) => {
461-
res.write(
462-
formatJournalData({
463-
command: 'FLAGGED_COUNTER',
464-
_id: lastEventId,
465-
total,
466-
unseen
467-
})
468-
);
469-
next();
470-
})
471-
.catch(() => next());
459+
try {
460+
const [total, unseen] = await Promise.all([tools.getFlaggedCounter(db, user), tools.getFlaggedCounter(db, user, 'unseen')]);
461+
res.write(
462+
formatJournalData({
463+
command: 'FLAGGED_COUNTER',
464+
_id: lastEventId,
465+
total,
466+
unseen
467+
})
468+
);
469+
} catch {
470+
// ignore
471+
}
472+
next();
472473
};
473474

474-
let emitKeywordCounters = next => {
475+
let emitKeywordCounters = async next => {
475476
if (!changedKeywords.size) {
476477
return next();
477478
}
478479

479-
const userKey = user.toString();
480-
Promise.all(
481-
[...changedKeywords].map(async keyword => {
482-
const isCached = await db.redis.exists(`kw:total:${userKey}:${keyword}`);
483-
return isCached ? keyword : null;
484-
})
485-
)
486-
.then(async results => {
487-
const toEmit = results.filter(Boolean);
488-
if (!toEmit.length) {
489-
return next();
490-
}
491-
492-
const keywordResults = await Promise.all(
493-
toEmit.map(async keyword => {
494-
let total, unseen;
495-
try {
496-
total = await tools.getKeywordCounter(db, user, keyword);
497-
} catch {
498-
total = 0;
499-
}
500-
try {
501-
unseen = await tools.getKeywordCounter(db, user, keyword, 'unseen');
502-
} catch {
503-
unseen = 0;
504-
}
505-
return { keyword, total, unseen };
506-
})
507-
);
480+
try {
481+
const userKey = user.toString();
482+
const cachedResults = await Promise.all(
483+
[...changedKeywords].map(async keyword => {
484+
const isCached = await db.redis.exists(`kw:total:${userKey}:${keyword}`);
485+
return isCached ? keyword : null;
486+
})
487+
);
488+
489+
const toEmit = cachedResults.filter(Boolean);
490+
if (!toEmit.length) {
491+
return next();
492+
}
508493

509-
for (const { keyword, total, unseen } of keywordResults) {
510-
let keywordEntry = {
511-
command: 'KEYWORD_COUNTERS',
512-
_id: lastEventId,
513-
keyword,
514-
total,
515-
unseen
516-
};
517-
res.write(formatJournalData(keywordEntry));
518-
onEntry('keyword-counters', keywordEntry);
519-
}
520-
next();
521-
})
522-
.catch(() => next());
494+
const keywordResults = await Promise.all(
495+
toEmit.map(async keyword => {
496+
let total, unseen;
497+
try {
498+
total = await tools.getKeywordCounter(db, user, keyword);
499+
} catch {
500+
total = 0;
501+
}
502+
try {
503+
unseen = await tools.getKeywordCounter(db, user, keyword, 'unseen');
504+
} catch {
505+
unseen = 0;
506+
}
507+
return { keyword, total, unseen };
508+
})
509+
);
510+
511+
for (const { keyword, total, unseen } of keywordResults) {
512+
let keywordEntry = {
513+
command: 'KEYWORD_COUNTERS',
514+
_id: lastEventId,
515+
keyword,
516+
total,
517+
unseen
518+
};
519+
res.write(formatJournalData(keywordEntry));
520+
onEntry('keyword-counters', keywordEntry);
521+
}
522+
} catch {
523+
// ignore
524+
}
525+
next();
523526
};
524527

525528
let cursor = db.database.collection('journal').find(query).sort({ _id: 1 });
@@ -612,6 +615,26 @@ function loadJournalStream(db, res, user, lastEventId, done, onEntry) {
612615
break;
613616
}
614617

618+
let writeEntryAndContinue = () => {
619+
try {
620+
let data = formatJournalData(e);
621+
res.write(data);
622+
onEntry('replay', e);
623+
} catch (err) {
624+
log.error(
625+
'API',
626+
'action=updates-event-write-fail user=%s event=%s payload=%s error=%s',
627+
user.toString(),
628+
formatLogValue(e.command),
629+
stringifyJournalPayload(e),
630+
err.stack || err
631+
);
632+
}
633+
634+
processed++;
635+
return setImmediate(processNext);
636+
};
637+
615638
for (const keyword of [...(e.keywords ?? []), ...(e.addedKeywords ?? []), ...(e.removedKeywords ?? [])]) {
616639
changedKeywords.add(keyword);
617640
}
@@ -624,23 +647,7 @@ function loadJournalStream(db, res, user, lastEventId, done, onEntry) {
624647
}
625648
}
626649

627-
try {
628-
let data = formatJournalData(e);
629-
res.write(data);
630-
onEntry('replay', e);
631-
} catch (err) {
632-
log.error(
633-
'API',
634-
'action=updates-event-write-fail user=%s event=%s payload=%s error=%s',
635-
user.toString(),
636-
formatLogValue(e.command),
637-
stringifyJournalPayload(e),
638-
err.stack || err
639-
);
640-
}
641-
642-
processed++;
643-
return setImmediate(processNext);
650+
writeEntryAndContinue();
644651
});
645652
};
646653

lib/filter-handler.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,8 @@ class FilterHandler {
289289
}
290290

291291
if (key === 'keywords') {
292-
let existingKeywords = filterActions.get('keywords') || [];
293-
let newKeywords = filterData.action[key] || [];
292+
let existingKeywords = filterActions.get('keywords') ?? [];
293+
let newKeywords = filterData.action[key] ?? [];
294294
filterActions.set('keywords', [...new Set([...existingKeywords, ...newKeywords])]);
295295
return;
296296
}
@@ -705,11 +705,11 @@ class FilterHandler {
705705
break;
706706
case 'keywords':
707707
if (Array.isArray(value) && value.length) {
708-
value.forEach(keyword => {
708+
for (let keyword of value) {
709709
if (!flags.includes(keyword)) {
710710
flags.push(keyword);
711711
}
712-
});
712+
}
713713
filterResults.push({ keywords: value });
714714
}
715715
break;

lib/handlers/on-copy.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ async function copyHandler(server, messageHandler, connection, mailbox, update,
295295
message: messageData._id,
296296
unseen: messageData.unseen,
297297
flagged: messageData.flagged,
298+
keywords: tools.extractKeywords(messageData.flags),
298299
idate: messageData.idate,
299300
thread: messageData.thread
300301
};

lib/handlers/on-store.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ module.exports = server => (mailbox, update, session, callback) => {
350350

351351
const currentKeywords = extractKeywords(message.flags);
352352
const addedKeywords = currentKeywords.filter(keyword => !oldKeywords.has(keyword));
353-
const removedKeywords = Array.from(oldKeywords).filter(keyword => !currentKeywords.includes(keyword));
353+
const removedKeywords = [...oldKeywords].filter(keyword => !currentKeywords.includes(keyword));
354354
const messageIsFlagged = message.flags.includes('\\Flagged');
355355

356356
const notifyEntry = {

lib/imap-notifier.js

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -539,11 +539,6 @@ class ImapNotifier extends EventEmitter {
539539
}
540540
}
541541

542-
getTrackedEntryKeywords(entryKeywords) {
543-
const keywords = entryKeywords ?? [];
544-
return [...new Set(keywords.filter(keyword => keyword && !consts.SYSTEM_FLAGS.has(keyword)))];
545-
}
546-
547542
addKeywordDelta(deltas, keyword, total, unseen) {
548543
if (!deltas.has(keyword)) {
549544
deltas.set(keyword, { total: 0, unseen: 0 });
@@ -563,31 +558,31 @@ class ImapNotifier extends EventEmitter {
563558

564559
switch (entry.command) {
565560
case 'EXISTS':
566-
for (let keyword of this.getTrackedEntryKeywords(entry.keywords)) {
561+
for (let keyword of tools.extractKeywords(entry.keywords)) {
567562
this.addKeywordDelta(deltas, keyword, 1, entry.unseen ? 1 : 0);
568563
}
569564
break;
570565

571566
case 'EXPUNGE':
572-
for (let keyword of this.getTrackedEntryKeywords(entry.keywords)) {
567+
for (let keyword of tools.extractKeywords(entry.keywords)) {
573568
this.addKeywordDelta(deltas, keyword, -1, entry.unseen ? -1 : 0);
574569
}
575570
break;
576571

577572
case 'FETCH': {
578573
const messageUnseen = !(entry.flags ?? []).includes('\\Seen');
579574

580-
for (let keyword of this.getTrackedEntryKeywords(entry.addedKeywords)) {
575+
for (let keyword of tools.extractKeywords(entry.addedKeywords)) {
581576
this.addKeywordDelta(deltas, keyword, 1, messageUnseen ? 1 : 0);
582577
}
583578

584-
for (let keyword of this.getTrackedEntryKeywords(entry.removedKeywords)) {
579+
for (let keyword of tools.extractKeywords(entry.removedKeywords)) {
585580
this.addKeywordDelta(deltas, keyword, -1, messageUnseen ? -1 : 0);
586581
}
587582

588583
if (entry.unseenChange) {
589584
const unseenStep = messageUnseen ? 1 : -1;
590-
for (let keyword of this.getTrackedEntryKeywords(entry.flags)) {
585+
for (let keyword of tools.extractKeywords(entry.flags)) {
591586
this.addKeywordDelta(deltas, keyword, 0, unseenStep);
592587
}
593588
}

lib/message-handler.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,13 +1768,13 @@ class MessageHandler {
17681768

17691769
const oldKeywords = new Set(tools.extractKeywords(messageData.flags));
17701770
const newKeywords = new Set(tools.extractKeywords(updatedMessageData.flags));
1771-
const messageWasSeen = (messageData.flags || []).includes('\\Seen');
1772-
const messageIsSeen = (updatedMessageData.flags || []).includes('\\Seen');
1773-
const messageWasFlagged = (messageData.flags || []).includes('\\Flagged');
1774-
const messageIsFlagged = (updatedMessageData.flags || []).includes('\\Flagged');
1771+
const messageWasSeen = (messageData.flags ?? []).includes('\\Seen');
1772+
const messageIsSeen = (updatedMessageData.flags ?? []).includes('\\Seen');
1773+
const messageWasFlagged = (messageData.flags ?? []).includes('\\Flagged');
1774+
const messageIsFlagged = (updatedMessageData.flags ?? []).includes('\\Flagged');
17751775

1776-
const addedKeywords = Array.from(newKeywords).filter(keyword => !oldKeywords.has(keyword));
1777-
const removedKeywords = Array.from(oldKeywords).filter(keyword => !newKeywords.has(keyword));
1776+
const addedKeywords = [...newKeywords].filter(keyword => !oldKeywords.has(keyword));
1777+
const removedKeywords = [...oldKeywords].filter(keyword => !newKeywords.has(keyword));
17781778

17791779
updatedCount++;
17801780

0 commit comments

Comments
 (0)