the "new-feed-entries" websocket event no longer needs to reload the entire tree

This commit is contained in:
Athou
2024-01-13 09:03:14 +01:00
parent 11dd151a3b
commit b0aa6ae524
5 changed files with 45 additions and 13 deletions

View File

@@ -26,6 +26,22 @@ export const treeSlice = createSlice({
toggleSidebar: state => {
state.sidebarVisible = !state.sidebarVisible
},
incrementUnreadCount: (
state,
action: PayloadAction<{
feedId: number
amount: number
}>
) => {
if (!state.rootCategory) return
visitCategoryTree(state.rootCategory, c =>
c.feeds
.filter(f => f.id === action.payload.feedId)
.forEach(f => {
f.unread += action.payload.amount
})
)
},
},
extraReducers: builder => {
builder.addCase(reloadTree.fulfilled, (state, action) => {
@@ -53,4 +69,4 @@ export const treeSlice = createSlice({
},
})
export const { setMobileMenuOpen, toggleSidebar } = treeSlice.actions
export const { setMobileMenuOpen, toggleSidebar, incrementUnreadCount } = treeSlice.actions

View File

@@ -1,9 +1,22 @@
import { setWebSocketConnected } from "app/server/slice"
import { useAppDispatch, useAppSelector } from "app/store"
import { reloadTree } from "app/tree/thunks"
import { type AppDispatch, useAppDispatch, useAppSelector } from "app/store"
import { incrementUnreadCount } from "app/tree/slice"
import { useEffect } from "react"
import WebsocketHeartbeatJs from "websocket-heartbeat-js"
const handleMessage = (dispatch: AppDispatch, message: string) => {
const parts = message.split(":")
const type = parts[0]
if (type === "new-feed-entries") {
dispatch(
incrementUnreadCount({
feedId: +parts[1],
amount: +parts[2],
})
)
}
}
export const useWebSocket = () => {
const websocketEnabled = useAppSelector(state => state.server.serverInfos?.websocketEnabled)
const websocketPingInterval = useAppSelector(state => state.server.serverInfos?.websocketPingInterval)
@@ -27,7 +40,7 @@ export const useWebSocket = () => {
ws.onmessage = event => {
const { data } = event
if (typeof data === "string") {
if (data.startsWith("new-feed-entries:")) dispatch(reloadTree())
handleMessage(dispatch, data)
}
}
}

View File

@@ -118,7 +118,7 @@ public class FeedRefreshUpdater {
public boolean update(Feed feed, List<Entry> entries) {
boolean processed = true;
boolean insertedAtLeastOneEntry = false;
long inserted = 0;
if (!entries.isEmpty()) {
Set<String> lastEntries = cache.getLastEntries(feed);
@@ -134,7 +134,7 @@ public class FeedRefreshUpdater {
}
AddEntryResult addEntryResult = addEntry(feed, entry, subscriptions);
processed &= addEntryResult.processed;
insertedAtLeastOneEntry |= addEntryResult.inserted;
inserted += addEntryResult.inserted ? 1 : 0;
entryCacheMiss.mark();
} else {
@@ -148,13 +148,12 @@ public class FeedRefreshUpdater {
if (subscriptions == null) {
feed.setMessage("No new entries found");
} else if (insertedAtLeastOneEntry) {
} else if (inserted > 0) {
List<User> users = subscriptions.stream().map(FeedSubscription::getUser).toList();
cache.invalidateUnreadCount(subscriptions.toArray(new FeedSubscription[0]));
cache.invalidateUserRootCategory(users.toArray(new User[0]));
// notify over websocket
subscriptions.forEach(sub -> webSocketSessions.sendMessage(sub.getUser(), WebSocketMessageBuilder.newFeedEntries(sub)));
notifyOverWebsocket(subscriptions, inserted);
}
}
@@ -163,7 +162,7 @@ public class FeedRefreshUpdater {
feed.setDisabledUntil(Instant.EPOCH);
}
if (insertedAtLeastOneEntry) {
if (inserted > 0) {
feedUpdated.mark();
}
@@ -172,6 +171,10 @@ public class FeedRefreshUpdater {
return processed;
}
private void notifyOverWebsocket(List<FeedSubscription> subscriptions, long inserted) {
subscriptions.forEach(sub -> webSocketSessions.sendMessage(sub.getUser(), WebSocketMessageBuilder.newFeedEntries(sub, inserted)));
}
@AllArgsConstructor
private static class AddEntryResult {
private final boolean processed;

View File

@@ -7,8 +7,8 @@ import lombok.experimental.UtilityClass;
@UtilityClass
public class WebSocketMessageBuilder {
public static String newFeedEntries(FeedSubscription subscription) {
return String.format("%s:%s", "new-feed-entries", subscription.getId());
public static String newFeedEntries(FeedSubscription subscription, long count) {
return String.format("%s:%s:%s", "new-feed-entries", subscription.getId(), count);
}
}

View File

@@ -66,7 +66,7 @@ class WebSocketIT extends BaseIT {
Long subscriptionId = subscribe(getFeedUrl());
Awaitility.await().atMost(15, TimeUnit.SECONDS).until(() -> messageRef.get() != null);
Assertions.assertEquals("new-feed-entries:" + subscriptionId, messageRef.get());
Assertions.assertEquals("new-feed-entries:" + subscriptionId + ":2", messageRef.get());
}
}