@@ -246,79 +246,137 @@ impl PrismDatasetRequest {
246
246
mut self ,
247
247
key : SessionKey ,
248
248
) -> Result < Vec < PrismDatasetResponse > , PrismLogstreamError > {
249
- let is_empty = self . streams . is_empty ( ) ;
250
- if is_empty {
249
+ if self . streams . is_empty ( ) {
251
250
self . streams = PARSEABLE . streams . list ( ) ;
252
251
}
253
252
254
- let mut responses = vec ! [ ] ;
255
- for stream in self . streams . iter ( ) {
256
- if Users . authorize ( key. clone ( ) , Action :: ListStream , Some ( stream) , None )
257
- != crate :: rbac:: Response :: Authorized
258
- {
259
- // Don't warn if listed from Parseable
260
- if !is_empty {
261
- warn ! ( "Unauthorized access requested for stream: {stream}" ) ;
262
- }
263
- continue ;
253
+ // Process streams concurrently
254
+ let results = futures:: future:: join_all (
255
+ self . streams
256
+ . iter ( )
257
+ . map ( |stream| self . process_stream ( stream. clone ( ) , key. clone ( ) ) ) ,
258
+ )
259
+ . await ;
260
+
261
+ // Collect successful responses and handle errors
262
+ let mut responses = Vec :: new ( ) ;
263
+ for result in results {
264
+ match result {
265
+ Some ( Ok ( response) ) => responses. push ( response) ,
266
+ Some ( Err ( err) ) => return Err ( err) ,
267
+ None => { } // Skip unauthorized or not found streams
264
268
}
269
+ }
265
270
266
- if PARSEABLE . check_or_load_stream ( stream) . await {
267
- debug ! ( "Stream not found: {stream}" ) ;
268
- continue ;
269
- }
271
+ Ok ( responses)
272
+ }
270
273
271
- let PrismLogstreamInfo {
272
- info,
273
- schema,
274
- stats,
275
- retention,
276
- } = get_prism_logstream_info ( stream) . await ?;
277
-
278
- let hottier = match HotTierManager :: global ( ) {
279
- Some ( manager) => match manager. get_hot_tier ( stream) . await {
280
- Ok ( stats) => Some ( stats) ,
281
- Err ( HotTierError :: HotTierValidationError (
282
- HotTierValidationError :: NotFound ( _) ,
283
- ) ) => None ,
284
- Err ( err) => return Err ( err. into ( ) ) ,
285
- } ,
286
- _ => None ,
287
- } ;
288
- let records = CountsRequest {
289
- stream : stream. clone ( ) ,
290
- start_time : "1h" . to_owned ( ) ,
291
- end_time : "now" . to_owned ( ) ,
292
- num_bins : 10 ,
293
- }
294
- . get_bin_density ( )
295
- . await ?;
296
- let counts = CountsResponse {
297
- fields : vec ! [ "start_time" . into( ) , "end_time" . into( ) , "count" . into( ) ] ,
298
- records,
299
- } ;
300
-
301
- // Retrieve distinct values for source identifiers
302
- // Returns None if fields aren't present or if query fails
303
- let ips = self . get_distinct_entries ( stream, "p_src_ip" ) . await . ok ( ) ;
304
- let user_agents = self . get_distinct_entries ( stream, "p_user_agent" ) . await . ok ( ) ;
305
-
306
- responses. push ( PrismDatasetResponse {
307
- stream : stream. clone ( ) ,
308
- info,
309
- schema,
310
- stats,
311
- retention,
312
- hottier,
313
- counts,
314
- distinct_sources : json ! ( {
315
- "ips" : ips,
316
- "user_agents" : user_agents
317
- } ) ,
318
- } )
274
+ async fn process_stream (
275
+ & self ,
276
+ stream : String ,
277
+ key : SessionKey ,
278
+ ) -> Option < Result < PrismDatasetResponse , PrismLogstreamError > > {
279
+ // Skip unauthorized streams
280
+ if !self . is_authorized ( & stream, & key) {
281
+ return None ;
319
282
}
320
283
321
- Ok ( responses)
284
+ // Skip streams that don't exist
285
+ if !self . stream_exists ( & stream) . await {
286
+ return None ;
287
+ }
288
+
289
+ // Process stream data
290
+ match get_prism_logstream_info ( & stream) . await {
291
+ Ok ( info) => Some ( self . build_dataset_response ( stream, info) . await ) ,
292
+ Err ( err) => Some ( Err ( err) ) ,
293
+ }
294
+ }
295
+
296
+ fn is_authorized ( & self , stream : & str , key : & SessionKey ) -> bool {
297
+ if Users . authorize ( key. clone ( ) , Action :: ListStream , Some ( stream) , None )
298
+ != crate :: rbac:: Response :: Authorized
299
+ {
300
+ warn ! ( "Unauthorized access requested for stream: {stream}" ) ;
301
+ false
302
+ } else {
303
+ true
304
+ }
305
+ }
306
+
307
+ async fn stream_exists ( & self , stream : & str ) -> bool {
308
+ if PARSEABLE . check_or_load_stream ( stream) . await {
309
+ debug ! ( "Stream not found: {stream}" ) ;
310
+ false
311
+ } else {
312
+ true
313
+ }
314
+ }
315
+
316
+ async fn build_dataset_response (
317
+ & self ,
318
+ stream : String ,
319
+ info : PrismLogstreamInfo ,
320
+ ) -> Result < PrismDatasetResponse , PrismLogstreamError > {
321
+ // Get hot tier info
322
+ let hottier = self . get_hot_tier_info ( & stream) . await ?;
323
+
324
+ // Get counts
325
+ let counts = self . get_counts ( & stream) . await ?;
326
+
327
+ // Get distinct entries concurrently
328
+ let ( ips_result, user_agents_result) = futures:: join!(
329
+ self . get_distinct_entries( & stream, "p_src_ip" ) ,
330
+ self . get_distinct_entries( & stream, "p_user_agent" )
331
+ ) ;
332
+
333
+ let ips = ips_result. ok ( ) ;
334
+ let user_agents = user_agents_result. ok ( ) ;
335
+
336
+ Ok ( PrismDatasetResponse {
337
+ stream,
338
+ info : info. info ,
339
+ schema : info. schema ,
340
+ stats : info. stats ,
341
+ retention : info. retention ,
342
+ hottier,
343
+ counts,
344
+ distinct_sources : json ! ( {
345
+ "ips" : ips,
346
+ "user_agents" : user_agents
347
+ } ) ,
348
+ } )
349
+ }
350
+
351
+ async fn get_hot_tier_info (
352
+ & self ,
353
+ stream : & str ,
354
+ ) -> Result < Option < StreamHotTier > , PrismLogstreamError > {
355
+ match HotTierManager :: global ( ) {
356
+ Some ( manager) => match manager. get_hot_tier ( stream) . await {
357
+ Ok ( stats) => Ok ( Some ( stats) ) ,
358
+ Err ( HotTierError :: HotTierValidationError ( HotTierValidationError :: NotFound ( _) ) ) => {
359
+ Ok ( None )
360
+ }
361
+ Err ( err) => Err ( err. into ( ) ) ,
362
+ } ,
363
+ None => Ok ( None ) ,
364
+ }
365
+ }
366
+
367
+ async fn get_counts ( & self , stream : & str ) -> Result < CountsResponse , PrismLogstreamError > {
368
+ let count_request = CountsRequest {
369
+ stream : stream. to_owned ( ) ,
370
+ start_time : "1h" . to_owned ( ) ,
371
+ end_time : "now" . to_owned ( ) ,
372
+ num_bins : 10 ,
373
+ } ;
374
+
375
+ let records = count_request. get_bin_density ( ) . await ?;
376
+ Ok ( CountsResponse {
377
+ fields : vec ! [ "start_time" . into( ) , "end_time" . into( ) , "count" . into( ) ] ,
378
+ records,
379
+ } )
322
380
}
323
381
324
382
/// Retrieves distinct values for a specific field in a stream.
0 commit comments