Fix IPC storm, DM filter fallback for old-format messages

- Active tab refreshes every 10s, badge counting every 30s (was double-loading all tabs every 10s)
- DM filter fallback: old posts without intentKind filtered from Feed/My Posts using legacy encrypted-for-me check
- Removed duplicate feed/myposts loading that caused CPU exhaustion on WebKitGTK

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Scott Reimers 2026-03-20 23:33:33 -04:00
parent 24b78a8d41
commit 075366e876

View file

@ -631,7 +631,7 @@ async function loadStats() {
async function loadFeed(force) { async function loadFeed(force) {
try { try {
const allPosts = await invoke('get_feed'); const allPosts = await invoke('get_feed');
const posts = allPosts.filter(p => p.intentKind !== 'direct'); const posts = allPosts.filter(p => p.intentKind !== 'direct' && !(p.intentKind === 'unknown' && (p.visibility === 'encrypted-for-me' || (p.isMe && p.recipients && p.recipients.length > 0))));
// Fingerprint: post IDs + reaction counts + comment counts // Fingerprint: post IDs + reaction counts + comment counts
const fp = posts.map(p => `${p.id}:${(p.reactionCounts||[]).map(r=>r.emoji+r.count).join(',')}:${p.commentCount||0}`).join('|'); const fp = posts.map(p => `${p.id}:${(p.reactionCounts||[]).map(r=>r.emoji+r.count).join(',')}:${p.commentCount||0}`).join('|');
if (!force && fp === _feedFingerprint) return; if (!force && fp === _feedFingerprint) return;
@ -687,20 +687,12 @@ async function loadFeed(force) {
} catch (e) { } catch (e) {
feedList.innerHTML = `<p class="status-err">Error: ${e}</p>`; feedList.innerHTML = `<p class="status-err">Error: ${e}</p>`;
} }
// Update feed badge if not currently viewing feed
if (currentTab !== 'feed' && _lastFeedViewMs > 0) {
try {
const allPosts = await invoke('get_feed');
const newCount = allPosts.filter(p => p.intentKind !== 'direct' && !p.isMe && p.timestampMs > _lastFeedViewMs).length;
updateTabBadge('feed', newCount);
} catch (_) {}
}
} }
async function loadMyPosts(force) { async function loadMyPosts(force) {
try { try {
const posts = await invoke('get_all_posts'); const posts = await invoke('get_all_posts');
const mine = posts.filter(p => p.isMe && p.intentKind !== 'direct'); const mine = posts.filter(p => p.isMe && p.intentKind !== 'direct' && !(p.intentKind === 'unknown' && p.recipients && p.recipients.length > 0));
const fp = mine.map(p => `${p.id}:${(p.reactionCounts||[]).map(r=>r.emoji+r.count).join(',')}:${p.commentCount||0}`).join('|'); const fp = mine.map(p => `${p.id}:${(p.reactionCounts||[]).map(r=>r.emoji+r.count).join(',')}:${p.commentCount||0}`).join('|');
if (!force && fp === _myPostsFingerprint) return; if (!force && fp === _myPostsFingerprint) return;
_myPostsFingerprint = fp; _myPostsFingerprint = fp;
@ -725,24 +717,6 @@ async function loadMyPosts(force) {
} }
} }
} }
// Count posts with new engagement (before marking as seen)
if (currentTab !== 'myposts') {
let newEngagement = 0;
for (const p of mine) {
const totalReacts = (p.reactionCounts || []).reduce((sum, r) => sum + r.count, 0);
const totalComments = p.commentCount || 0;
if (totalReacts > 0 || totalComments > 0) {
try {
const seen = await invoke('get_seen_engagement', { postId: p.id });
if (totalReacts > (seen.seenReactCount || 0) || totalComments > (seen.seenCommentCount || 0)) {
newEngagement++;
}
} catch (_) { newEngagement++; }
}
}
updateTabBadge('myposts', newEngagement);
}
// Mark all visible own posts' engagement as seen (DB-backed) when viewing tab // Mark all visible own posts' engagement as seen (DB-backed) when viewing tab
if (currentTab === 'myposts') { if (currentTab === 'myposts') {
for (const p of mine) { for (const p of mine) {
@ -2994,17 +2968,44 @@ async function init() {
// Initial network indicator // Initial network indicator
updateNetworkIndicator(); updateNetworkIndicator();
// Auto-refresh every 10 seconds // Auto-refresh every 10 seconds — only the active tab
setInterval(() => { setInterval(() => {
if (currentTab === 'feed') loadFeed(); if (currentTab === 'feed') loadFeed();
if (currentTab === 'myposts') loadMyPosts(); if (currentTab === 'myposts') loadMyPosts();
if (currentTab === 'people') { loadFollows(); loadPeers(); loadAudience(); } if (currentTab === 'people') { loadFollows(); loadPeers(); loadAudience(); }
updateNetworkIndicator(); updateNetworkIndicator();
// Update badges for non-active tabs
if (currentTab !== 'feed') loadFeed();
if (currentTab !== 'myposts') loadMyPosts();
}, 10000); }, 10000);
// Badge updates for non-active tabs — every 30 seconds (lightweight)
setInterval(async () => {
try {
// Feed badge
if (currentTab !== 'feed' && _lastFeedViewMs > 0) {
const allPosts = await invoke('get_feed');
const isDM = p => p.intentKind === 'direct' || (p.intentKind === 'unknown' && (p.visibility === 'encrypted-for-me' || (p.isMe && p.recipients && p.recipients.length > 0)));
const newCount = allPosts.filter(p => !isDM(p) && !p.isMe && p.timestampMs > _lastFeedViewMs).length;
updateTabBadge('feed', newCount);
}
// My Posts badge (new engagement)
if (currentTab !== 'myposts') {
const posts = await invoke('get_all_posts');
const mine = posts.filter(p => p.isMe && p.intentKind !== 'direct' && !(p.intentKind === 'unknown' && p.recipients && p.recipients.length > 0));
let newEngagement = 0;
for (const p of mine) {
const totalReacts = (p.reactionCounts || []).reduce((sum, r) => sum + r.count, 0);
const totalComments = p.commentCount || 0;
if (totalReacts > 0 || totalComments > 0) {
try {
const seen = await invoke('get_seen_engagement', { postId: p.id });
if (totalReacts > (seen.seenReactCount || 0) || totalComments > (seen.seenCommentCount || 0)) newEngagement++;
} catch (_) { newEngagement++; }
}
}
updateTabBadge('myposts', newEngagement);
}
} catch (_) {}
}, 30000);
// Tiered DM polling: frequency based on recency of last message // Tiered DM polling: frequency based on recency of last message
let _lastMsgPollMs = 0; let _lastMsgPollMs = 0;
setInterval(() => { setInterval(() => {