Sasha commited on
Commit
adbcce3
·
1 Parent(s): 9fb93a9

perf: reduce egress by caching stats endpoints longer and limiting getChatMessages

Browse files
Files changed (2) hide show
  1. server/db.js +38 -27
  2. server/server.js +8 -8
server/db.js CHANGED
@@ -1302,41 +1302,52 @@ export async function getChatMessages(streamId = null) {
1302
  if (streamId) {
1303
  return sqliteDb.prepare('SELECT message, username, display_name, timestamp FROM messages WHERE stream_id = ? AND username NOT IN (?, ?)').all(streamId, ...bots);
1304
  } else {
1305
- return sqliteDb.prepare('SELECT message, username, display_name, timestamp FROM messages WHERE username NOT IN (?, ?)').all(...bots);
1306
  }
1307
  } else {
1308
- let allData = [];
1309
- let from = 0;
1310
- const limit = 1000;
1311
-
1312
- while(true) {
1313
- let query = supabase
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1314
  .from('messages')
1315
  .select('message, username, display_name, timestamp')
1316
  .not('username', 'in', `(${bots.map(b => `"${b}"`).join(',')})`)
1317
- .range(from, from + limit - 1);
1318
-
1319
- if (streamId) {
1320
- query = query.eq('stream_id', streamId);
1321
- }
1322
-
1323
- const { data, error } = await query;
1324
-
1325
  if (error) {
1326
- console.error('[Supabase] Error getting chat messages:', error);
1327
- break;
1328
- }
1329
-
1330
- if (data && data.length > 0) {
1331
- allData = allData.concat(data);
1332
- if (data.length < limit) break; // Fetched the last incomplete page
1333
- from += limit;
1334
- } else {
1335
- break; // Empty page
1336
  }
 
1337
  }
1338
-
1339
- return allData;
1340
  }
1341
  }
1342
 
 
1302
  if (streamId) {
1303
  return sqliteDb.prepare('SELECT message, username, display_name, timestamp FROM messages WHERE stream_id = ? AND username NOT IN (?, ?)').all(streamId, ...bots);
1304
  } else {
1305
+ return sqliteDb.prepare('SELECT message, username, display_name, timestamp FROM messages WHERE username NOT IN (?, ?) ORDER BY timestamp DESC LIMIT 10000').all(...bots);
1306
  }
1307
  } else {
1308
+ if (streamId) {
1309
+ let allData = [];
1310
+ let from = 0;
1311
+ const limit = 1000;
1312
+
1313
+ while(true) {
1314
+ const { data, error } = await supabase
1315
+ .from('messages')
1316
+ .select('message, username, display_name, timestamp')
1317
+ .eq('stream_id', streamId)
1318
+ .not('username', 'in', `(${bots.map(b => `"${b}"`).join(',')})`)
1319
+ .range(from, from + limit - 1);
1320
+
1321
+ if (error) {
1322
+ console.error('[Supabase] Error getting chat messages:', error);
1323
+ break;
1324
+ }
1325
+
1326
+ if (data && data.length > 0) {
1327
+ allData = allData.concat(data);
1328
+ if (data.length < limit) break; // Fetched the last incomplete page
1329
+ from += limit;
1330
+ } else {
1331
+ break; // Empty page
1332
+ }
1333
+ }
1334
+
1335
+ return allData;
1336
+ } else {
1337
+ // Global query (All streams) - limit to 10,000 most recent messages to prevent huge egress
1338
+ const { data, error } = await supabase
1339
  .from('messages')
1340
  .select('message, username, display_name, timestamp')
1341
  .not('username', 'in', `(${bots.map(b => `"${b}"`).join(',')})`)
1342
+ .order('timestamp', { ascending: false })
1343
+ .limit(10000);
1344
+
 
 
 
 
 
1345
  if (error) {
1346
+ console.error('[Supabase] Error getting global chat messages:', error);
1347
+ return [];
 
 
 
 
 
 
 
 
1348
  }
1349
+ return data || [];
1350
  }
 
 
1351
  }
1352
  }
1353
 
server/server.js CHANGED
@@ -623,13 +623,13 @@ app.get('/api/auth/logout', (req, res) => {
623
  // =========================================================================
624
 
625
  // Get list of streams
626
- app.get('/api/streams', cacheMiddleware(), async (req, res) => {
627
  const streams = await getStreamsList();
628
  res.json(streams);
629
  });
630
 
631
  // Get top active chatters
632
- app.get('/api/stats/chatters', cacheMiddleware(), async (req, res) => {
633
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
634
  const limit = req.query.limit ? parseInt(req.query.limit) : 50;
635
 
@@ -638,7 +638,7 @@ app.get('/api/stats/chatters', cacheMiddleware(), async (req, res) => {
638
  });
639
 
640
  // Get true total summary statistics
641
- app.get('/api/stats/summary', cacheMiddleware(), async (req, res) => {
642
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
643
  try {
644
  const summary = await getStatsSummary(streamId);
@@ -691,7 +691,7 @@ const WORD_MAPPINGS = {
691
  };
692
 
693
  // Get word frequencies (Voice vs Chat messages from streamer)
694
- app.get('/api/stats/words', cacheMiddleware(), async (req, res) => {
695
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
696
  const limit = req.query.limit ? parseInt(req.query.limit) : 50;
697
  const type = req.query.type || 'voice'; // 'voice' or 'chat'
@@ -785,7 +785,7 @@ app.get('/api/stats/words', cacheMiddleware(), async (req, res) => {
785
  });
786
 
787
  // Get chat activity (messages count grouped by 5-minute intervals)
788
- app.get('/api/stats/activity', cacheMiddleware(), async (req, res) => {
789
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
790
 
791
  if (!streamId) {
@@ -823,7 +823,7 @@ app.get('/api/stats/activity', cacheMiddleware(), async (req, res) => {
823
  // =========================================================================
824
 
825
  // Get log of moderator actions
826
- app.get('/api/stats/moderators', requireModeratorRole, async (req, res) => {
827
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
828
  const limit = req.query.limit ? parseInt(req.query.limit) : 100;
829
 
@@ -832,7 +832,7 @@ app.get('/api/stats/moderators', requireModeratorRole, async (req, res) => {
832
  });
833
 
834
  // Get summary counts of actions per moderator
835
- app.get('/api/stats/moderators/summary', requireModeratorRole, async (req, res) => {
836
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
837
 
838
  const data = await getModActionsSummaryRaw(streamId);
@@ -863,7 +863,7 @@ app.get('/api/stats/moderators/summary', requireModeratorRole, async (req, res)
863
  });
864
 
865
  // GET aggregated profiles with scores for moderators
866
- app.get('/api/stats/moderators/profiles', cacheMiddleware(), async (req, res) => {
867
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
868
  const profiles = await getModeratorProfilesData(streamId);
869
  res.json(profiles);
 
623
  // =========================================================================
624
 
625
  // Get list of streams
626
+ app.get('/api/streams', cacheMiddleware(120), async (req, res) => {
627
  const streams = await getStreamsList();
628
  res.json(streams);
629
  });
630
 
631
  // Get top active chatters
632
+ app.get('/api/stats/chatters', cacheMiddleware(300), async (req, res) => {
633
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
634
  const limit = req.query.limit ? parseInt(req.query.limit) : 50;
635
 
 
638
  });
639
 
640
  // Get true total summary statistics
641
+ app.get('/api/stats/summary', cacheMiddleware(120), async (req, res) => {
642
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
643
  try {
644
  const summary = await getStatsSummary(streamId);
 
691
  };
692
 
693
  // Get word frequencies (Voice vs Chat messages from streamer)
694
+ app.get('/api/stats/words', cacheMiddleware(600), async (req, res) => {
695
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
696
  const limit = req.query.limit ? parseInt(req.query.limit) : 50;
697
  const type = req.query.type || 'voice'; // 'voice' or 'chat'
 
785
  });
786
 
787
  // Get chat activity (messages count grouped by 5-minute intervals)
788
+ app.get('/api/stats/activity', cacheMiddleware(300), async (req, res) => {
789
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
790
 
791
  if (!streamId) {
 
823
  // =========================================================================
824
 
825
  // Get log of moderator actions
826
+ app.get('/api/stats/moderators', requireModeratorRole, cacheMiddleware(300), async (req, res) => {
827
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
828
  const limit = req.query.limit ? parseInt(req.query.limit) : 100;
829
 
 
832
  });
833
 
834
  // Get summary counts of actions per moderator
835
+ app.get('/api/stats/moderators/summary', requireModeratorRole, cacheMiddleware(300), async (req, res) => {
836
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
837
 
838
  const data = await getModActionsSummaryRaw(streamId);
 
863
  });
864
 
865
  // GET aggregated profiles with scores for moderators
866
+ app.get('/api/stats/moderators/profiles', cacheMiddleware(300), async (req, res) => {
867
  const streamId = req.query.stream_id ? parseInt(req.query.stream_id) : null;
868
  const profiles = await getModeratorProfilesData(streamId);
869
  res.json(profiles);