detached 17f3fb1

fix: offline status not updating in public buddy list view

commit
17f3fb182e17d1bd12be107a521a3d67f8de9eb1
author
Kit · · 2025-02-17 10:25 UTC
parent
42d61be
signature
SSH UnverifiedSHA256:H91DFuEG4jpk5edzLA4aUKkpv4zv9Q339ipRmkph6Tk The key is unknown
2 files · +40 -16
M src/lib/states/chat.svelte.ts +1 -0
@@ -35,6 +35,7 @@ class ChatState {
3535 private lastBuddyListUpdate = 0;
3636 private lastBuddyListHash = '';
3737 private hasMoreMessages = $state(false);
38+ private publicPollingInterval: ReturnType<typeof setInterval> | null = null;
3839
3940 public async reinitialize() {
4041 if (this.isInitializing) {
@@ -35,6 +35,7 @@ class ChatState {
35 private lastBuddyListUpdate = 0;35 private lastBuddyListUpdate = 0;
36 private lastBuddyListHash = '';36 private lastBuddyListHash = '';
37 private hasMoreMessages = $state(false);37 private hasMoreMessages = $state(false);
38+ private publicPollingInterval: ReturnType<typeof setInterval> | null = null;
38 39
39 public async reinitialize() {40 public async reinitialize() {
40 if (this.isInitializing) {41 if (this.isInitializing) {
M src/routes/api/rooms/[roomId]/+server.ts +39 -16
@@ -7,6 +7,8 @@ import { createLogger } from '$lib/utils/logger.server';
77
88 const log = createLogger('rooms-server');
99
10+const ONLINE_TIMEOUT_MS = 2 * 60 * 1000; // 2 minutes
11+
1012 export async function GET({ params, url, locals }): Promise<Response> {
1113 const { roomId } = params;
1214 const isPublic = !locals.user || url.searchParams.get('public') === 'true';
@@ -18,25 +20,45 @@ export async function GET({ params, url, locals }): Promise<Response> {
1820 requestedBy: locals.user ? `${locals.user.id.slice(0, 4)}...${locals.user.id.slice(-4)}` : 'public'
1921 });
2022
21- // Fetch messages for the room (most recent then reversed for chronological order)
22- const messageQuery = db.select()
23- .from(messages)
24- .where(eq(messages.chatRoomId, roomId))
25- .orderBy(desc(messages.timestamp));
26-
27- // Limit messages for public requests
28- if (isPublic) {
29- messageQuery.limit(10);
30- } else {
31- messageQuery.limit(50);
32- }
23+ // Calculate timeout threshold
24+ const timeoutThreshold = Date.now() - ONLINE_TIMEOUT_MS;
3325
34- // Fetch buddy list: get all users in the room (including offline)
26+ // Fetch buddy list: get all users and mark them as offline if they've timed out
3527 const fetchedUsers = await db.select()
36- .from(users);
28+ .from(users)
29+ .execute();
30+
31+ // Process users to mark them as offline if they've timed out
32+ const processedUsers = fetchedUsers.map(user => {
33+ const shouldBeOffline = user.status === 'online' && user.lastSeen < timeoutThreshold;
34+ return {
35+ ...user,
36+ status: shouldBeOffline ? 'offline' : user.status
37+ };
38+ });
39+
40+ // Update any users that should be offline in the database
41+ const usersToUpdate = processedUsers.filter(user =>
42+ user.status === 'offline' &&
43+ fetchedUsers.find(u => u.id === user.id)?.status === 'online'
44+ );
45+
46+ if (usersToUpdate.length > 0) {
47+ await Promise.all(usersToUpdate.map(user =>
48+ db.update(users)
49+ .set({ status: 'offline', lastSeen: Date.now() })
50+ .where(eq(users.id, user.id))
51+ .execute()
52+ ));
53+
54+ log.debug('Updated offline status for users', {
55+ count: usersToUpdate.length,
56+ userIds: usersToUpdate.map(u => u.id)
57+ });
58+ }
3759
3860 // Sanitize user data using createSafeUser
39- const sanitizedUsers = fetchedUsers.map(user => createSafeUser(user));
61+ const sanitizedUsers = processedUsers.map(user => createSafeUser(user));
4062
4163 const responseData: PublicRoomResponse = {
4264 success: true,
@@ -46,7 +68,8 @@ export async function GET({ params, url, locals }): Promise<Response> {
4668 log.debug('Successfully fetched room data', {
4769 roomId,
4870 userCount: sanitizedUsers.length,
49- isPublic
71+ isPublic,
72+ offlineUpdates: usersToUpdate.length
5073 });
5174
5275 return new Response(JSON.stringify(responseData), {
@@ -7,6 +7,8 @@ import { createLogger } from '$lib/utils/logger.server';
7 7
8 const log = createLogger('rooms-server');8 const log = createLogger('rooms-server');
9 9
10+const ONLINE_TIMEOUT_MS = 2 * 60 * 1000; // 2 minutes
11+
10 export async function GET({ params, url, locals }): Promise<Response> {12 export async function GET({ params, url, locals }): Promise<Response> {
11 const { roomId } = params;13 const { roomId } = params;
12 const isPublic = !locals.user || url.searchParams.get('public') === 'true';14 const isPublic = !locals.user || url.searchParams.get('public') === 'true';
@@ -18,25 +20,45 @@ export async function GET({ params, url, locals }): Promise<Response> {
18 requestedBy: locals.user ? `${locals.user.id.slice(0, 4)}...${locals.user.id.slice(-4)}` : 'public'20 requestedBy: locals.user ? `${locals.user.id.slice(0, 4)}...${locals.user.id.slice(-4)}` : 'public'
19 });21 });
20 22
21- // Fetch messages for the room (most recent then reversed for chronological order)23+ // Calculate timeout threshold
22- const messageQuery = db.select()24+ const timeoutThreshold = Date.now() - ONLINE_TIMEOUT_MS;
23- .from(messages)
24- .where(eq(messages.chatRoomId, roomId))
25- .orderBy(desc(messages.timestamp));
26-
27- // Limit messages for public requests
28- if (isPublic) {
29- messageQuery.limit(10);
30- } else {
31- messageQuery.limit(50);
32- }
33 25
34- // Fetch buddy list: get all users in the room (including offline)26+ // Fetch buddy list: get all users and mark them as offline if they've timed out
35 const fetchedUsers = await db.select()27 const fetchedUsers = await db.select()
36- .from(users);28+ .from(users)
29+ .execute();
30+
31+ // Process users to mark them as offline if they've timed out
32+ const processedUsers = fetchedUsers.map(user => {
33+ const shouldBeOffline = user.status === 'online' && user.lastSeen < timeoutThreshold;
34+ return {
35+ ...user,
36+ status: shouldBeOffline ? 'offline' : user.status
37+ };
38+ });
39+
40+ // Update any users that should be offline in the database
41+ const usersToUpdate = processedUsers.filter(user =>
42+ user.status === 'offline' &&
43+ fetchedUsers.find(u => u.id === user.id)?.status === 'online'
44+ );
45+
46+ if (usersToUpdate.length > 0) {
47+ await Promise.all(usersToUpdate.map(user =>
48+ db.update(users)
49+ .set({ status: 'offline', lastSeen: Date.now() })
50+ .where(eq(users.id, user.id))
51+ .execute()
52+ ));
53+
54+ log.debug('Updated offline status for users', {
55+ count: usersToUpdate.length,
56+ userIds: usersToUpdate.map(u => u.id)
57+ });
58+ }
37 59
38 // Sanitize user data using createSafeUser60 // Sanitize user data using createSafeUser
39- const sanitizedUsers = fetchedUsers.map(user => createSafeUser(user));61+ const sanitizedUsers = processedUsers.map(user => createSafeUser(user));
40 62
41 const responseData: PublicRoomResponse = {63 const responseData: PublicRoomResponse = {
42 success: true,64 success: true,
@@ -46,7 +68,8 @@ export async function GET({ params, url, locals }): Promise<Response> {
46 log.debug('Successfully fetched room data', { 68 log.debug('Successfully fetched room data', {
47 roomId,69 roomId,
48 userCount: sanitizedUsers.length,70 userCount: sanitizedUsers.length,
49- isPublic71+ isPublic,
72+ offlineUpdates: usersToUpdate.length
50 });73 });
51 74
52 return new Response(JSON.stringify(responseData), {75 return new Response(JSON.stringify(responseData), {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 3

Tags 8

↑↓ moveenter openesc close