using Inspectron.Epson.PrintServer.ConfigurationSources; using Microsoft.Extensions.Logging; using System.Net.Http.Json; using System.Text.Json.Serialization; namespace EpsonPrintService; /// /// Background task that periodically sends heartbeat signals to the API /// public class HeartbeatBackgroundTask { private readonly EpsonPrintServiceConfiguration _configuration; private readonly ILogger _logger; private readonly HttpClient _httpClient; private readonly TimeSpan _interval; public HeartbeatBackgroundTask( EpsonPrintServiceConfiguration configuration, ILogger logger, HttpClient httpClient) { _configuration = configuration; _logger = logger; _httpClient = httpClient; _interval = TimeSpan.FromSeconds(30); } /// /// Starts the heartbeat background task /// /// Token to cancel the background task public async Task StartAsync(CancellationToken cancellationToken) { _logger.LogInformation("Starting heartbeat background task (interval: {Interval}s)", _interval.TotalSeconds); // Run immediately on start await SendHeartbeatAsync(); // Then run periodically while (!cancellationToken.IsCancellationRequested) { try { await Task.Delay(_interval, cancellationToken); await SendHeartbeatAsync(); } catch (TaskCanceledException) { break; } catch (Exception ex) { _logger.LogError(ex, "Error during heartbeat"); } } _logger.LogInformation("Heartbeat background task stopped"); } private async Task SendHeartbeatAsync() { try { var url = _configuration.ApiUrl != null ? $"{_configuration.ApiUrl.TrimEnd('/')}/api/printerServer/heartbeat" : null; var apiKey = _configuration.ApiKey; if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(apiKey)) { _logger.LogWarning("Heartbeat not configured (missing ApiUrl or ApiKey)"); return; } using var request = new HttpRequestMessage(HttpMethod.Post, url); request.Headers.Add("X-Printer-Server-Key", apiKey); var payload = new HeartbeatPayload { OsVersion = Environment.OSVersion.ToString() }; request.Content = JsonContent.Create(payload); var response = await _httpClient.SendAsync(request); if (response.IsSuccessStatusCode) { _logger.LogDebug("Heartbeat sent successfully"); } else { _logger.LogWarning("Heartbeat failed with status code: {StatusCode}", response.StatusCode); } } catch (Exception ex) { _logger.LogWarning(ex, "Failed to send heartbeat"); } } private class HeartbeatPayload { [JsonPropertyName("osVersion")] public string OsVersion { get; set; } = string.Empty; } }