From 681e1aa3e946053975c1dee4ec3467575a31de97 Mon Sep 17 00:00:00 2001 From: MasterDraco Date: Wed, 12 Mar 2025 21:56:43 +0000 Subject: [PATCH] Simplify MetricsService implementation to remove database dependencies --- src/Services/MetricsService.cs | 715 +++------------------------------ 1 file changed, 65 insertions(+), 650 deletions(-) diff --git a/src/Services/MetricsService.cs b/src/Services/MetricsService.cs index 657c6ed..91ba461 100644 --- a/src/Services/MetricsService.cs +++ b/src/Services/MetricsService.cs @@ -1,528 +1,91 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading; using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using TransmissionRssManager.Core; -using TransmissionRssManager.Data.Repositories; namespace TransmissionRssManager.Services { + /// + /// Interface for the metrics service that provides dashboard statistics and performance data + /// public interface IMetricsService { - Task GetDashboardStatsAsync(); - Task> GetDownloadHistoryAsync(int days = 30); - Task> GetCategoryStatsAsync(); - Task GetSystemStatusAsync(); + Task> GetDashboardStatsAsync(); Task> EstimateDiskUsageAsync(); - Task> GetPerformanceMetricsAsync(); + Task> GetSystemStatusAsync(); } + /// + /// Service that provides metrics and statistics about downloads, system status, and performance + /// public class MetricsService : IMetricsService { private readonly ILogger _logger; private readonly ITransmissionClient _transmissionClient; - private readonly IRepository _feedRepository; - private readonly IRepository _feedItemRepository; - private readonly IRepository _torrentRepository; - private readonly IRepository _logRepository; - private readonly ILoggingService _loggingService; private readonly IConfigService _configService; - // Helper method to map database Torrent model to Core.TorrentInfo - private Core.TorrentInfo MapToTorrentInfo(TransmissionRssManager.Data.Models.Torrent torrent) - { - return new Core.TorrentInfo - { - Id = torrent.Id, - Name = torrent.Name, - Status = torrent.Status, - PercentDone = torrent.PercentDone, - TotalSize = torrent.TotalSize, - DownloadDir = torrent.DownloadDirectory ?? "", - AddedDate = torrent.AddedOn, - CompletedDate = torrent.CompletedOn, - DownloadedEver = torrent.DownloadedEver, - UploadedEver = torrent.UploadedEver, - UploadRatio = (int)torrent.UploadRatio, - ErrorString = torrent.ErrorMessage ?? "", - HashString = torrent.Hash, - PeersConnected = torrent.PeersConnected, - DownloadSpeed = torrent.DownloadSpeed, - UploadSpeed = torrent.UploadSpeed, - Category = torrent.Category ?? "", - HasMetadata = torrent.HasMetadata, - TransmissionInstance = torrent.TransmissionInstance ?? "default", - SourceFeedId = torrent.RssFeedItemId?.ToString() ?? "", - IsPostProcessed = torrent.PostProcessed - }; - } - - // Helper method to map database RssFeed model to Core.RssFeed - private Core.RssFeed MapToRssFeed(TransmissionRssManager.Data.Models.RssFeed feed) - { - var result = new Core.RssFeed - { - Id = feed.Id.ToString(), - Name = feed.Name, - Url = feed.Url, - AutoDownload = feed.Enabled, - LastChecked = feed.LastCheckedAt, - TransmissionInstanceId = feed.TransmissionInstanceId ?? "default", - Schedule = feed.Schedule, - Enabled = feed.Enabled, - MaxHistoryItems = feed.MaxHistoryItems, - DefaultCategory = feed.DefaultCategory ?? "", - ErrorCount = feed.ErrorCount, - LastError = feed.LastError != null ? feed.LastCheckedAt : null, - LastErrorMessage = feed.LastError - }; - - // Add rules to the feed - if (feed.Rules != null) - { - foreach (var rule in feed.Rules) - { - result.AdvancedRules.Add(new Core.RssFeedRule - { - Id = rule.Id.ToString(), - Name = rule.Name, - Pattern = rule.IncludePattern ?? "", - IsRegex = rule.UseRegex, - IsEnabled = rule.Enabled, - IsCaseSensitive = false, // Default value as this field doesn't exist in the DB model - Category = rule.CustomSavePath ?? "", - Priority = rule.Priority, - Action = rule.EnablePostProcessing ? "process" : "download", - DestinationFolder = rule.CustomSavePath ?? "" - }); - } - } - - return result; - } - public MetricsService( ILogger logger, ITransmissionClient transmissionClient, - IRepository feedRepository, - IRepository feedItemRepository, - IRepository torrentRepository, - IRepository logRepository, - ILoggingService loggingService, IConfigService configService) { _logger = logger; _transmissionClient = transmissionClient; - _feedRepository = feedRepository; - _feedItemRepository = feedItemRepository; - _torrentRepository = torrentRepository; - _logRepository = logRepository; - _loggingService = loggingService; _configService = configService; } - public async Task GetDashboardStatsAsync() + /// + /// Gets dashboard statistics including active downloads, upload/download speeds, etc. + /// + public async Task> GetDashboardStatsAsync() { try { - var now = DateTime.UtcNow; - var today = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0, DateTimeKind.Utc); + var stats = new Dictionary(); + var torrents = await _transmissionClient.GetTorrentsAsync(); - // Combine data from both Transmission and database - // Get active torrents from Transmission for real-time data - var transmissionTorrents = await _transmissionClient.GetTorrentsAsync(); + // Calculate basic stats + stats["TotalTorrents"] = torrents.Count; + stats["ActiveDownloads"] = torrents.Count(t => t.Status == "Downloading"); + stats["SeedingTorrents"] = torrents.Count(t => t.Status == "Seeding"); + stats["CompletedTorrents"] = torrents.Count(t => t.IsFinished); + stats["TotalDownloaded"] = torrents.Sum(t => t.DownloadedEver); + stats["TotalUploaded"] = torrents.Sum(t => t.UploadedEver); + stats["DownloadSpeed"] = torrents.Sum(t => t.DownloadSpeed); + stats["UploadSpeed"] = torrents.Sum(t => t.UploadSpeed); - // Get database torrent data for historical information - var dbTorrents = await _torrentRepository.Query().ToListAsync(); + // Calculate total size + long totalSize = torrents.Sum(t => t.TotalSize); + stats["TotalSize"] = totalSize; - // Count active downloads (status is downloading) - var activeDownloads = transmissionTorrents.Count(t => t.Status == "Downloading"); - - // Count seeding torrents (status is seeding) - var seedingTorrents = transmissionTorrents.Count(t => t.Status == "Seeding"); - - // Get active feeds count - var activeFeeds = await _feedRepository.Query() - .Where(f => f.Enabled) - .CountAsync(); - - // Get completed downloads today - var completedToday = dbTorrents - .Count(t => t.CompletedOn.HasValue && t.CompletedOn.Value >= today); - - // Get added today - var addedToday = dbTorrents - .Count(t => t.AddedOn >= today); - - // Get matched count (all time) - var matchedCount = await _feedItemRepository.Query() - .Where(i => i.MatchedRuleId != null) - .CountAsync(); - - // Calculate download/upload speeds from Transmission (real-time data) - double downloadSpeed = transmissionTorrents.Sum(t => t.DownloadSpeed); - double uploadSpeed = transmissionTorrents.Sum(t => t.UploadSpeed); - - // Update database objects with transmission data - // This helps keep database in sync with transmission for metrics - foreach (var transmissionTorrent in transmissionTorrents) - { - var dbTorrent = dbTorrents.FirstOrDefault(t => t.TransmissionId == transmissionTorrent.Id); - if (dbTorrent != null) - { - // Update database with current speeds and status for the background service to store - dbTorrent.DownloadSpeed = transmissionTorrent.DownloadSpeed; - dbTorrent.UploadSpeed = transmissionTorrent.UploadSpeed; - dbTorrent.Status = transmissionTorrent.Status; - dbTorrent.PercentDone = transmissionTorrent.PercentDone; - dbTorrent.DownloadedEver = transmissionTorrent.DownloadedEver; - dbTorrent.UploadedEver = transmissionTorrent.UploadedEver; - dbTorrent.PeersConnected = transmissionTorrent.PeersConnected; - - // Update the database object - await _torrentRepository.UpdateAsync(dbTorrent); - } - } - - // Save the changes - await _torrentRepository.SaveChangesAsync(); - - // Calculate total downloaded and uploaded - // Use Transmission for active torrents (more accurate) and database for historical torrents - var totalDownloaded = transmissionTorrents.Sum(t => t.DownloadedEver); - var totalUploaded = transmissionTorrents.Sum(t => t.UploadedEver); - - // Add historical data from database for torrents that are no longer in Transmission - var transmissionIds = transmissionTorrents.Select(t => t.Id).ToHashSet(); - var historicalTorrents = dbTorrents.Where(t => t.TransmissionId.HasValue && !transmissionIds.Contains(t.TransmissionId.Value)); - totalDownloaded += historicalTorrents.Sum(t => t.DownloadedEver); - totalUploaded += historicalTorrents.Sum(t => t.UploadedEver); - - return new DashboardStats - { - ActiveDownloads = activeDownloads, - SeedingTorrents = seedingTorrents, - ActiveFeeds = activeFeeds, - CompletedToday = completedToday, - AddedToday = addedToday, - FeedsCount = await _feedRepository.Query().CountAsync(), - MatchedCount = matchedCount, - DownloadSpeed = downloadSpeed, - UploadSpeed = uploadSpeed, - TotalDownloaded = totalDownloaded, - TotalUploaded = totalUploaded - }; + return stats; } catch (Exception ex) { _logger.LogError(ex, "Error getting dashboard stats"); - _loggingService.Log( - LogLevel.Error, - $"Error getting dashboard stats: {ex.Message}", - "MetricsService", - new Dictionary { - { "ErrorMessage", ex.Message }, - { "StackTrace", ex.StackTrace } - } - ); - - return new DashboardStats(); - } - } - - public async Task> GetDownloadHistoryAsync(int days = 30) - { - try - { - var result = new List(); - var endDate = DateTime.UtcNow; - var startDate = endDate.AddDays(-days); - - // Get download history from the database for added torrents - var addedTorrents = await _torrentRepository.Query() - .Where(t => t.AddedOn >= startDate && t.AddedOn <= endDate) - .ToListAsync(); - - // Get completed torrents history - var completedTorrents = await _torrentRepository.Query() - .Where(t => t.CompletedOn.HasValue && t.CompletedOn.Value >= startDate && t.CompletedOn.Value <= endDate) - .ToListAsync(); - - // Group by date added - var groupedByAdded = addedTorrents - .GroupBy(t => new DateTime(t.AddedOn.Year, t.AddedOn.Month, t.AddedOn.Day, 0, 0, 0, DateTimeKind.Utc)) - .Select(g => new { - Date = g.Key, - Count = g.Count(), - TotalSize = g.Sum(t => t.TotalSize) - }) - .OrderBy(g => g.Date) - .ToList(); - - // Group by date completed - var groupedByCompleted = completedTorrents - .GroupBy(t => new DateTime(t.CompletedOn.Value.Year, t.CompletedOn.Value.Month, t.CompletedOn.Value.Day, 0, 0, 0, DateTimeKind.Utc)) - .Select(g => new { - Date = g.Key, - Count = g.Count(), - TotalSize = g.Sum(t => t.TotalSize) - }) - .OrderBy(g => g.Date) - .ToList(); - - // Fill in missing dates - for (var date = startDate; date <= endDate; date = date.AddDays(1)) + return new Dictionary { - var day = new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Utc); - - // Get data for this day - var addedData = groupedByAdded.FirstOrDefault(g => g.Date == day); - var completedData = groupedByCompleted.FirstOrDefault(g => g.Date == day); - - // Create data point with added count and size - result.Add(new HistoricalDataPoint - { - Date = day, - Count = addedData?.Count ?? 0, // Use added count by default - TotalSize = addedData?.TotalSize ?? 0, - CompletedCount = completedData?.Count ?? 0, - CompletedSize = completedData?.TotalSize ?? 0 - }); - } - - return result; - } - catch (Exception ex) - { - _logger.LogError(ex, "Error getting download history"); - _loggingService.Log( - LogLevel.Error, - $"Error getting download history: {ex.Message}", - "MetricsService", - new Dictionary { - { "ErrorMessage", ex.Message }, - { "StackTrace", ex.StackTrace }, - { "Days", days.ToString() } - } - ); - - return new List(); + ["Error"] = ex.Message, + ["TotalTorrents"] = 0, + ["ActiveDownloads"] = 0, + ["SeedingTorrents"] = 0, + ["CompletedTorrents"] = 0 + }; } } - public async Task> GetCategoryStatsAsync() - { - try - { - // Get torrents with categories from database - var dbTorrents = await _torrentRepository.Query() - .Where(t => t.Category != null) - .ToListAsync(); - - // Get torrents from Transmission for real-time data - var transmissionTorrents = await _transmissionClient.GetTorrentsAsync(); - - // Map Transmission torrents to dictionary by hash for quick lookup - var transmissionTorrentsByHash = transmissionTorrents - .Where(t => !string.IsNullOrEmpty(t.HashString)) - .ToDictionary(t => t.HashString, t => t); - - // Create a list to store category stats with combined data - var categoryStats = new Dictionary(); - - // Process database torrents first - foreach (var torrent in dbTorrents) - { - var category = torrent.Category ?? "Uncategorized"; - - if (!categoryStats.TryGetValue(category, out var stats)) - { - stats = new CategoryStats - { - Category = category, - Count = 0, - TotalSize = 0, - ActiveCount = 0, - CompletedCount = 0, - DownloadSpeed = 0, - UploadSpeed = 0 - }; - categoryStats[category] = stats; - } - - stats.Count++; - stats.TotalSize += torrent.TotalSize; - - // Check if this torrent is completed - if (torrent.CompletedOn.HasValue) - { - stats.CompletedCount++; - } - - // Check if this torrent is active in Transmission - if (transmissionTorrentsByHash.TryGetValue(torrent.Hash, out var transmissionTorrent)) - { - stats.ActiveCount++; - stats.DownloadSpeed += transmissionTorrent.DownloadSpeed; - stats.UploadSpeed += transmissionTorrent.UploadSpeed; - } - } - - // Process any Transmission torrents that might not be in the database - foreach (var torrent in transmissionTorrents) - { - // Skip if no hash or already processed - if (string.IsNullOrEmpty(torrent.HashString) || - dbTorrents.Any(t => t.Hash == torrent.HashString)) - { - continue; - } - - var category = torrent.Category ?? "Uncategorized"; - - if (!categoryStats.TryGetValue(category, out var stats)) - { - stats = new CategoryStats - { - Category = category, - Count = 0, - TotalSize = 0, - ActiveCount = 0, - CompletedCount = 0, - DownloadSpeed = 0, - UploadSpeed = 0 - }; - categoryStats[category] = stats; - } - - stats.Count++; - stats.TotalSize += torrent.TotalSize; - stats.ActiveCount++; - stats.DownloadSpeed += torrent.DownloadSpeed; - stats.UploadSpeed += torrent.UploadSpeed; - - // Check if this torrent is completed - if (torrent.IsFinished) - { - stats.CompletedCount++; - } - } - - // Return the category stats ordered by count - return categoryStats.Values - .OrderByDescending(c => c.Count) - .ToList(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error getting category stats"); - _loggingService.Log( - LogLevel.Error, - $"Error getting category stats: {ex.Message}", - "MetricsService", - new Dictionary { - { "ErrorMessage", ex.Message }, - { "StackTrace", ex.StackTrace } - } - ); - - return new List(); - } - } - - public async Task GetSystemStatusAsync() - { - var config = _configService.GetConfiguration(); - - var status = new SystemStatus - { - TransmissionConnected = false, - AutoDownloadEnabled = config.AutoDownloadEnabled, - PostProcessingEnabled = config.PostProcessing.Enabled, - EnabledFeeds = await _feedRepository.Query().Where(f => f.Enabled).CountAsync(), - TotalFeeds = await _feedRepository.Query().CountAsync(), - CheckIntervalMinutes = config.CheckIntervalMinutes, - NotificationsEnabled = config.UserPreferences.NotificationsEnabled, - DatabaseStatus = "Connected" - }; - - try - { - // Check database health by counting torrents - var torrentCount = await _torrentRepository.Query().CountAsync(); - status.TorrentCount = torrentCount; - - // Count torrents by status - status.ActiveTorrentCount = await _torrentRepository.Query() - .Where(t => t.Status == "downloading" || t.Status == "Downloading") - .CountAsync(); - - status.CompletedTorrentCount = await _torrentRepository.Query() - .Where(t => t.CompletedOn.HasValue) - .CountAsync(); - - // Check feed items count - status.FeedItemCount = await _feedItemRepository.Query().CountAsync(); - - // Check log entries count - var logCount = await _logRepository.Query().CountAsync(); - status.LogEntryCount = logCount; - - // Get database size estimate (rows * avg row size) - long estimatedDbSize = (torrentCount * 1024) + (status.FeedItemCount * 512) + (logCount * 256); - status.EstimatedDatabaseSizeBytes = estimatedDbSize; - - // Try to connect to Transmission to check if it's available - var torrents = await _transmissionClient.GetTorrentsAsync(); - - status.TransmissionConnected = true; - status.TransmissionVersion = "Unknown"; // We don't have a way to get this info directly - status.TransmissionTorrentCount = torrents.Count; - - // Enhancement: Map any transmission torrents not in our database - var dbTorrents = await _torrentRepository.Query().ToListAsync(); - var transmissionHashes = torrents.Select(t => t.HashString).ToHashSet(); - var dbHashes = dbTorrents.Select(t => t.Hash).ToHashSet(); - - status.OrphanedTorrentCount = transmissionHashes.Count(h => !dbHashes.Contains(h)); - status.StaleDbTorrentCount = dbHashes.Count(h => !transmissionHashes.Contains(h)); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error getting system status"); - status.TransmissionConnected = false; - status.LastErrorMessage = ex.Message; - } - - return status; - } - + /// + /// Estimates disk usage for torrents and available space + /// public async Task> EstimateDiskUsageAsync() { try { - // Get disk usage from both Transmission and database - var transmissionTorrents = await _transmissionClient.GetTorrentsAsync(); - var dbTorrents = await _torrentRepository.Query().ToListAsync(); - - // Calculate total size from Transmission (most accurate for active torrents) - long transmissionSize = transmissionTorrents.Sum(t => t.TotalSize); - - // Add sizes from database for torrents not in Transmission (historical data) - var transmissionHashes = transmissionTorrents.Select(t => t.HashString).ToHashSet(); - var historicalTorrents = dbTorrents.Where(t => !transmissionHashes.Contains(t.Hash)); - - long historicalSize = historicalTorrents.Sum(t => t.TotalSize); - - // Also get estimated database size - long databaseSize = await _torrentRepository.Query().CountAsync() * 1024 + // ~1KB per torrent - await _feedItemRepository.Query().CountAsync() * 512 + // ~512B per feed item - await _logRepository.Query().CountAsync() * 256; // ~256B per log entry + // Get disk usage from torrents + var torrents = await _transmissionClient.GetTorrentsAsync(); + long totalSize = torrents.Sum(t => t.TotalSize); // Calculate available space in download directory string downloadDir = _configService.GetConfiguration().DownloadDirectory; @@ -543,204 +106,56 @@ namespace TransmissionRssManager.Services return new Dictionary { - ["activeTorrentsSize"] = transmissionSize, - ["historicalTorrentsSize"] = historicalSize, - ["totalTorrentsSize"] = transmissionSize + historicalSize, - ["databaseSize"] = databaseSize, + ["activeTorrentsSize"] = totalSize, ["availableSpace"] = availableSpace }; } catch (Exception ex) { _logger.LogError(ex, "Error estimating disk usage"); - _loggingService.Log( - LogLevel.Error, - $"Error estimating disk usage: {ex.Message}", - "MetricsService", - new Dictionary { - { "ErrorMessage", ex.Message }, - { "StackTrace", ex.StackTrace } - } - ); - return new Dictionary { ["activeTorrentsSize"] = 0, - ["historicalTorrentsSize"] = 0, - ["totalTorrentsSize"] = 0, - ["databaseSize"] = 0, ["availableSpace"] = 0 }; } } - public async Task> GetPerformanceMetricsAsync() + /// + /// Gets system status including Transmission connection state + /// + public async Task> GetSystemStatusAsync() { - var metrics = new Dictionary(); + var config = _configService.GetConfiguration(); + + var status = new Dictionary + { + ["TransmissionConnected"] = false, + ["AutoDownloadEnabled"] = config.AutoDownloadEnabled, + ["PostProcessingEnabled"] = config.PostProcessing.Enabled, + ["CheckIntervalMinutes"] = config.CheckIntervalMinutes + }; try { - // Calculate average time to complete downloads - var completedTorrents = await _torrentRepository.Query() - .Where(t => t.CompletedOn.HasValue) - .ToListAsync(); + // Try to connect to Transmission to check if it's available + var torrents = await _transmissionClient.GetTorrentsAsync(); - if (completedTorrents.Any()) - { - var avgCompletionTimeMinutes = completedTorrents - .Where(t => t.AddedOn < t.CompletedOn) - .Average(t => (t.CompletedOn.Value - t.AddedOn).TotalMinutes); - - metrics["AvgCompletionTimeMinutes"] = Math.Round(avgCompletionTimeMinutes, 2); - } - else - { - metrics["AvgCompletionTimeMinutes"] = 0; - } + status["TransmissionConnected"] = true; + status["TransmissionTorrentCount"] = torrents.Count; - // Calculate feed refresh performance - var feeds = await _feedRepository.Query().ToListAsync(); - if (feeds.Any()) - { - var avgItemsPerFeed = await _feedItemRepository.Query().CountAsync() / (double)feeds.Count; - metrics["AvgItemsPerFeed"] = Math.Round(avgItemsPerFeed, 2); - } - else - { - metrics["AvgItemsPerFeed"] = 0; - } - - return metrics; + // Count torrents by status + status["ActiveTorrentCount"] = torrents.Count(t => t.Status == "Downloading"); + status["CompletedTorrentCount"] = torrents.Count(t => t.IsFinished); } catch (Exception ex) { - _logger.LogError(ex, "Error getting performance metrics"); - return new Dictionary - { - ["AvgCompletionTimeMinutes"] = 0, - ["AvgItemsPerFeed"] = 0 - }; - } - } - } - - public class DashboardStats - { - public int ActiveDownloads { get; set; } - public int SeedingTorrents { get; set; } - public int ActiveFeeds { get; set; } - public int CompletedToday { get; set; } - public int AddedToday { get; set; } - public int FeedsCount { get; set; } - public int MatchedCount { get; set; } - public double DownloadSpeed { get; set; } - public double UploadSpeed { get; set; } - public long TotalDownloaded { get; set; } - public long TotalUploaded { get; set; } - } - - public class HistoricalDataPoint - { - public DateTime Date { get; set; } - public int Count { get; set; } - public long TotalSize { get; set; } - public int CompletedCount { get; set; } - public long CompletedSize { get; set; } - } - - public class CategoryStats - { - public string Category { get; set; } - public int Count { get; set; } - public long TotalSize { get; set; } - public int ActiveCount { get; set; } - public int CompletedCount { get; set; } - public double DownloadSpeed { get; set; } - public double UploadSpeed { get; set; } - } - - public class SystemStatus - { - public bool TransmissionConnected { get; set; } - public string TransmissionVersion { get; set; } - public bool AutoDownloadEnabled { get; set; } - public bool PostProcessingEnabled { get; set; } - public int EnabledFeeds { get; set; } - public int TotalFeeds { get; set; } - public int CheckIntervalMinutes { get; set; } - public bool NotificationsEnabled { get; set; } - - // Database status - public string DatabaseStatus { get; set; } - public int TorrentCount { get; set; } - public int ActiveTorrentCount { get; set; } - public int CompletedTorrentCount { get; set; } - public int FeedItemCount { get; set; } - public int LogEntryCount { get; set; } - public long EstimatedDatabaseSizeBytes { get; set; } - - // Transmission status - public int TransmissionTorrentCount { get; set; } - - // Sync status - public int OrphanedTorrentCount { get; set; } // Torrents in Transmission but not in database - public int StaleDbTorrentCount { get; set; } // Torrents in database but not in Transmission - - // For compatibility - public string TranmissionVersion - { - get => TransmissionVersion; - set => TransmissionVersion = value; - } - - // Error info - public string LastErrorMessage { get; set; } - } - - public class MetricsBackgroundService : BackgroundService - { - private readonly ILogger _logger; - private readonly IServiceProvider _serviceProvider; - - public MetricsBackgroundService( - ILogger logger, - IServiceProvider serviceProvider) - { - _logger = logger; - _serviceProvider = serviceProvider; - } - - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - _logger.LogInformation("Metrics background service started"); - - // Update metrics every minute - var timer = new PeriodicTimer(TimeSpan.FromMinutes(1)); - - while (!stoppingToken.IsCancellationRequested && await timer.WaitForNextTickAsync(stoppingToken)) - { - try - { - using var scope = _serviceProvider.CreateScope(); - var metricsService = scope.ServiceProvider.GetRequiredService(); - - // This just ensures the metrics are calculated and cached if needed - await metricsService.GetDashboardStatsAsync(); - - _logger.LogDebug("Metrics updated"); - } - catch (OperationCanceledException) - { - // Service is shutting down - break; - } - catch (Exception ex) - { - _logger.LogError(ex, "Error updating metrics"); - } + _logger.LogError(ex, "Error getting system status"); + status["TransmissionConnected"] = false; + status["LastErrorMessage"] = ex.Message; } - _logger.LogInformation("Metrics background service stopped"); + return status; } } } \ No newline at end of file