veza/veza-backend-api/internal/services/bandwidth_detection_service.go
2025-12-03 20:29:37 +01:00

136 lines
3.8 KiB
Go

package services
import (
"context"
"sync"
"time"
"go.uber.org/zap"
)
// BandwidthDetectionService gère la détection de bande passante réseau
// T0347: Create Network Bandwidth Detection Service
type BandwidthDetectionService struct {
samples []int64
maxSamples int
mutex sync.RWMutex
logger *zap.Logger
}
// NewBandwidthDetectionService crée un nouveau service de détection de bande passante
func NewBandwidthDetectionService(logger *zap.Logger) *BandwidthDetectionService {
if logger == nil {
logger = zap.NewNop()
}
return &BandwidthDetectionService{
samples: make([]int64, 0, 10),
maxSamples: 10,
logger: logger,
}
}
// MeasureBandwidth mesure la bande passante en bps (bits per second)
// bytesTransferred: nombre d'octets transférés
// duration: durée du transfert
// Retourne la moyenne de bande passante en bps
func (s *BandwidthDetectionService) MeasureBandwidth(ctx context.Context, bytesTransferred int64, duration time.Duration) int64 {
if duration <= 0 {
s.logger.Warn("Invalid duration for bandwidth measurement", zap.Duration("duration", duration))
return 0
}
if bytesTransferred < 0 {
s.logger.Warn("Invalid bytes transferred for bandwidth measurement", zap.Int64("bytes", bytesTransferred))
return 0
}
// Calculer la bande passante en bps (bits per second)
// bytesTransferred * 8 pour convertir en bits
// duration.Seconds() pour obtenir la durée en secondes
seconds := duration.Seconds()
if seconds <= 0 {
return 0
}
// Utiliser float64 pour éviter les problèmes de précision avec les durées très courtes
bandwidth := int64((float64(bytesTransferred) * 8.0) / seconds)
s.mutex.Lock()
defer s.mutex.Unlock()
// Ajouter l'échantillon
s.samples = append(s.samples, bandwidth)
// Limiter le nombre d'échantillons
if len(s.samples) > s.maxSamples {
s.samples = s.samples[1:]
}
// Calculer et retourner la moyenne
return s.calculateAverage()
}
// calculateAverage calcule la moyenne des échantillons de bande passante
func (s *BandwidthDetectionService) calculateAverage() int64 {
if len(s.samples) == 0 {
return 0
}
var sum int64
for _, sample := range s.samples {
sum += sample
}
return sum / int64(len(s.samples))
}
// GetAverageBandwidth retourne la moyenne actuelle de bande passante sans ajouter de nouvel échantillon
func (s *BandwidthDetectionService) GetAverageBandwidth() int64 {
s.mutex.RLock()
defer s.mutex.RUnlock()
return s.calculateAverage()
}
// RecommendBitrate recommande un bitrate optimal en kbps basé sur la bande passante disponible
// bandwidth: bande passante en bps (bits per second)
// Retourne le bitrate recommandé en kbps
func (s *BandwidthDetectionService) RecommendBitrate(bandwidth int64) int {
if bandwidth <= 0 {
// Par défaut, retourner le bitrate le plus bas
return 128
}
// Réserver 20% de buffer pour éviter les problèmes de réseau
available := float64(bandwidth) * 0.8
// Convertir en kbps pour la comparaison
availableKbps := available / 1000.0
// Recommander le bitrate le plus élevé possible selon la bande passante disponible
// Les bitrates standards sont: 128, 192, 320 kbps
if availableKbps >= 320 {
return 320
} else if availableKbps >= 192 {
return 192
} else if availableKbps >= 128 {
return 128
}
// Si la bande passante est très faible, retourner quand même 128 kbps
// (le client devra gérer la mise en buffer)
return 128
}
// ClearSamples efface tous les échantillons de bande passante
func (s *BandwidthDetectionService) ClearSamples() {
s.mutex.Lock()
defer s.mutex.Unlock()
s.samples = make([]int64, 0, s.maxSamples)
}
// GetSampleCount retourne le nombre d'échantillons actuels
func (s *BandwidthDetectionService) GetSampleCount() int {
s.mutex.RLock()
defer s.mutex.RUnlock()
return len(s.samples)
}