@@ -336,16 +336,18 @@ def get_play_urls(self, play_domain: str, bucket: str, stream_name: str) -> Dict
336336 "message" : "Playback URLs generated successfully"
337337 }
338338
339- async def query_live_traffic_stats (self , begin : str , end : str ) -> Dict [str , Any ]:
339+ async def query_live_traffic_stats (self , begin : str , end : str , include_raw_data : bool = False ) -> Dict [str , Any ]:
340340 """
341341 Query live streaming traffic statistics
342342
343343 Args:
344344 begin: Start time in format YYYYMMDDHHMMSS (e.g., 20240101000000)
345345 end: End time in format YYYYMMDDHHMMSS (e.g., 20240129105148)
346+ include_raw_data: If True, includes raw JSON data for download (default: False)
346347
347348 Returns:
348- Dict containing traffic statistics
349+ Dict containing traffic statistics with total traffic (bytes), average bandwidth (bps),
350+ peak bandwidth (bps), and optionally raw data
349351 """
350352 if not self .live_endpoint :
351353 self .live_endpoint = "mls.cn-east-1.qiniumiku.com"
@@ -375,14 +377,99 @@ async def query_live_traffic_stats(self, begin: str, end: str) -> Dict[str, Any]
375377
376378 if status == 200 :
377379 logger .info ("Successfully queried live traffic stats" )
378- return {
379- "status" : "success" ,
380- "begin" : begin ,
381- "end" : end ,
382- "data" : text ,
383- "message" : "Traffic statistics retrieved successfully" ,
384- "status_code" : status
385- }
380+
381+ try :
382+ # Parse JSON response
383+ data = json .loads (text )
384+
385+ # Calculate total traffic and bandwidth metrics
386+ total_traffic_bytes = 0
387+ bandwidth_values = []
388+ data_points = []
389+
390+ # Data format: [{"time":"2025-11-26T00:00:00+08:00","values":{"flow":0}}, ...]
391+ for item in data :
392+ if isinstance (item , dict ) and "values" in item and "flow" in item ["values" ]:
393+ flow_bytes = item ["values" ]["flow" ]
394+ total_traffic_bytes += flow_bytes
395+
396+ # Convert to bandwidth: flow is accumulated over 5 minutes (300 seconds)
397+ # Bandwidth (bps) = bytes / 300 seconds * 8 bits/byte
398+ bandwidth_bps = (flow_bytes / 300 ) * 8
399+ bandwidth_values .append (bandwidth_bps )
400+
401+ # Store data point with timestamp
402+ data_points .append ({
403+ "time" : item .get ("time" , "" ),
404+ "traffic_bytes" : flow_bytes ,
405+ "bandwidth_bps" : bandwidth_bps
406+ })
407+
408+ # Calculate average and peak bandwidth
409+ avg_bandwidth_bps = sum (bandwidth_values ) / len (bandwidth_values ) if bandwidth_values else 0
410+ peak_bandwidth_bps = max (bandwidth_values ) if bandwidth_values else 0
411+
412+ # Convert to human-readable units
413+ def format_bytes (bytes_val ):
414+ """Convert bytes to human-readable format"""
415+ for unit in ['B' , 'KB' , 'MB' , 'GB' , 'TB' ]:
416+ if bytes_val < 1024.0 :
417+ return f"{ bytes_val :.2f} { unit } "
418+ bytes_val /= 1024.0
419+ return f"{ bytes_val :.2f} PB"
420+
421+ def format_bandwidth (bps ):
422+ """Convert bits per second to human-readable format"""
423+ for unit in ['bps' , 'Kbps' , 'Mbps' , 'Gbps' , 'Tbps' ]:
424+ if bps < 1000.0 :
425+ return f"{ bps :.2f} { unit } "
426+ bps /= 1000.0
427+ return f"{ bps :.2f} Pbps"
428+
429+ result = {
430+ "status" : "success" ,
431+ "begin" : begin ,
432+ "end" : end ,
433+ "summary" : {
434+ "total_traffic_bytes" : total_traffic_bytes ,
435+ "total_traffic_formatted" : format_bytes (total_traffic_bytes ),
436+ "data_points_count" : len (data_points ),
437+ "average_bandwidth_bps" : avg_bandwidth_bps ,
438+ "average_bandwidth_formatted" : format_bandwidth (avg_bandwidth_bps ),
439+ "peak_bandwidth_bps" : peak_bandwidth_bps ,
440+ "peak_bandwidth_formatted" : format_bandwidth (peak_bandwidth_bps ),
441+ "granularity" : "5 minutes"
442+ },
443+ "message" : "Traffic statistics calculated successfully" ,
444+ "status_code" : status
445+ }
446+
447+ # Include raw data only if requested
448+ if include_raw_data :
449+ result ["raw_data" ] = data
450+ result ["data_points" ] = data_points
451+
452+ return result
453+
454+ except json .JSONDecodeError as e :
455+ logger .error (f"Failed to parse JSON response: { e } " )
456+ return {
457+ "status" : "error" ,
458+ "begin" : begin ,
459+ "end" : end ,
460+ "message" : f"Failed to parse traffic stats response: { str (e )} " ,
461+ "raw_response" : text ,
462+ "status_code" : status
463+ }
464+ except Exception as e :
465+ logger .error (f"Error processing traffic stats: { e } " )
466+ return {
467+ "status" : "error" ,
468+ "begin" : begin ,
469+ "end" : end ,
470+ "message" : f"Error processing traffic stats: { str (e )} " ,
471+ "status_code" : status
472+ }
386473 else :
387474 logger .error (f"Failed to query traffic stats, status: { status } , response: { text } " )
388475 return {
0 commit comments