// Package routes provides data processing functions for EVE PI endpoints. package routes import ( "context" "fmt" "time" "go-eve-pi/esi" logger "git.site.quack-lab.dev/dave/cylogger" ) // ExtractorInfo represents extractor information for a planet type ExtractorInfo struct { PlanetName string `json:"planet_name"` ExtractorNumber int `json:"extractor_number"` ExpiryDate string `json:"expiry_date"` } // StorageInfo represents storage information for a planet type StorageInfo struct { PlanetName string `json:"planet_name"` StorageType string `json:"storage_type"` Utilization float64 `json:"utilization"` } // GetExtractorsForCharacter retrieves extractor information for a character func GetExtractorsForCharacter(esiClient esi.ESIInterface, characterID int, accessToken string) ([]ExtractorInfo, error) { logger.Debug("Getting extractors for character ID %d", characterID) // Get character planets planets, err := esiClient.GetCharacterPlanets(context.Background(), characterID, accessToken) if err != nil { logger.Error("Failed to get planets for character %d: %v", characterID, err) return nil, err } var extractors []ExtractorInfo for _, planet := range planets { // Get planet details details, err := esiClient.GetPlanetDetails(context.Background(), characterID, planet.PlanetID, accessToken) if err != nil { logger.Warning("Failed to fetch details for planet %d: %v", planet.PlanetID, err) continue } if details != nil { // Get planet name from universe endpoint planetNameData, err := esiClient.GetPlanetName(context.Background(), planet.PlanetID) if err != nil { logger.Error("Failed to get planet name for planet ID %d: %v", planet.PlanetID, err) continue } // Count extractors and get expiry dates extractorCount := 0 for _, pin := range details.Pins { if pin.ExtractorDetails != nil { extractorCount++ expiryDate := "N/A" if pin.ExpiryTime != nil { expiryDate = *pin.ExpiryTime } extractors = append(extractors, ExtractorInfo{ PlanetName: planetNameData.Name, ExtractorNumber: extractorCount, ExpiryDate: expiryDate, }) } } } } return extractors, nil } // GetStorageForCharacter retrieves storage information for a character func GetStorageForCharacter(esiClient esi.ESIInterface, characterID int, accessToken string) ([]StorageInfo, error) { logger.Debug("Getting storage for character ID %d", characterID) // Get character planets planets, err := esiClient.GetCharacterPlanets(context.Background(), characterID, accessToken) if err != nil { logger.Error("Failed to get planets for character %d: %v", characterID, err) return nil, err } var storage []StorageInfo for _, planet := range planets { // Get planet details details, err := esiClient.GetPlanetDetails(context.Background(), characterID, planet.PlanetID, accessToken) if err != nil { logger.Warning("Failed to fetch details for planet %d: %v", planet.PlanetID, err) continue } if details != nil { // Get planet name from universe endpoint planetNameData, err := esiClient.GetPlanetName(context.Background(), planet.PlanetID) if err != nil { logger.Error("Failed to get planet name for planet ID %d: %v", planet.PlanetID, err) continue } // Analyze storage utilization for _, pin := range details.Pins { if len(pin.Contents) > 0 { // Calculate utilization based on contents totalAmount := 0 for _, content := range pin.Contents { totalAmount += content.Amount } // Determine storage type based on pin type storageType := "Unknown" switch pin.TypeID { case 2254, 2255, 2256: // Launch pads storageType = "Launch Pad" case 2524, 2525, 2526: // Storage facilities storageType = "Storage" } // Calculate utilization percentage (assuming max capacity of 10000) utilization := float64(totalAmount) / 10000.0 * 100.0 if utilization > 100.0 { utilization = 100.0 } storage = append(storage, StorageInfo{ PlanetName: planetNameData.Name, StorageType: storageType, Utilization: utilization, }) } } } } return storage, nil } // CheckStorageThresholds checks storage utilization against thresholds func CheckStorageThresholds(storage []StorageInfo, warningThreshold, criticalThreshold float64) []StorageInfo { var alerts []StorageInfo for _, s := range storage { if s.Utilization >= criticalThreshold { alerts = append(alerts, s) } else if s.Utilization >= warningThreshold { alerts = append(alerts, s) } } return alerts } // CheckExtractorExpiry checks extractor expiry against thresholds func CheckExtractorExpiry(extractors []ExtractorInfo, warningDuration, criticalDuration time.Duration) []ExtractorInfo { var alerts []ExtractorInfo now := time.Now() for _, e := range extractors { if e.ExpiryDate == "N/A" { continue } expiryTime, err := time.Parse("2006-01-02 15:04:05", e.ExpiryDate) if err != nil { logger.Warning("Failed to parse expiry date %s: %v", e.ExpiryDate, err) continue } timeUntilExpiry := expiryTime.Sub(now) if timeUntilExpiry <= criticalDuration { alerts = append(alerts, e) } else if timeUntilExpiry <= warningDuration { alerts = append(alerts, e) } } return alerts } // FormatStorageAlert formats a storage alert message func FormatStorageAlert(storage StorageInfo, isCritical bool) string { severity := "WARNING" if isCritical { severity = "CRITICAL" } return fmt.Sprintf("🚨 %s: %s almost full on %s! (%.1f%% utilized)", severity, storage.StorageType, storage.PlanetName, storage.Utilization) } // FormatExtractorAlert formats an extractor alert message func FormatExtractorAlert(extractor ExtractorInfo, isCritical bool) string { severity := "WARNING" if isCritical { severity = "CRITICAL" } status := "expiring soon" if isCritical { status = "expired" } return fmt.Sprintf("⏰ %s: Extractor #%d %s on %s! (expires: %s)", severity, extractor.ExtractorNumber, status, extractor.PlanetName, extractor.ExpiryDate) }