- System tray app z NotifyIcon + ContextMenuStrip - Polling API orderPRO (GET /api/print/jobs/pending) - Pobieranie etykiet PDF i druk przez PdfiumViewer - Formularz ustawień: URL API, klucz, drukarka, interwał - Okno logów z historią (ciemny motyw, Consolas) - Self-contained .NET 8 publish (win-x64) - Milestone v0.7 Zdalne drukowanie etykiet — COMPLETE Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
160 lines
4.7 KiB
C#
160 lines
4.7 KiB
C#
using OrderPROPrint.Forms;
|
|
|
|
namespace OrderPROPrint.Services;
|
|
|
|
public class PollingService
|
|
{
|
|
private readonly PrintApiClient _apiClient;
|
|
private readonly PrintService _printService;
|
|
private readonly string _printerName;
|
|
private readonly int _intervalSeconds;
|
|
private readonly Action<string> _onStatusUpdate;
|
|
private readonly Action<string> _onError;
|
|
|
|
private System.Threading.Timer? _timer;
|
|
private bool _isProcessing;
|
|
private int _totalPrinted;
|
|
private readonly object _lock = new();
|
|
|
|
public bool IsRunning { get; private set; }
|
|
|
|
public PollingService(
|
|
PrintApiClient apiClient,
|
|
PrintService printService,
|
|
string printerName,
|
|
int intervalSeconds,
|
|
Action<string> onStatusUpdate,
|
|
Action<string> onError)
|
|
{
|
|
_apiClient = apiClient;
|
|
_printService = printService;
|
|
_printerName = printerName;
|
|
_intervalSeconds = Math.Max(intervalSeconds, 5);
|
|
_onStatusUpdate = onStatusUpdate;
|
|
_onError = onError;
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
if (IsRunning) return;
|
|
|
|
IsRunning = true;
|
|
_timer = new System.Threading.Timer(
|
|
async _ => await PollAsync(),
|
|
null,
|
|
TimeSpan.Zero,
|
|
TimeSpan.FromSeconds(_intervalSeconds)
|
|
);
|
|
|
|
_onStatusUpdate($"Aktywne (co {_intervalSeconds}s)");
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
IsRunning = false;
|
|
_timer?.Change(Timeout.Infinite, Timeout.Infinite);
|
|
_timer?.Dispose();
|
|
_timer = null;
|
|
}
|
|
|
|
private async Task PollAsync()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
if (_isProcessing) return;
|
|
_isProcessing = true;
|
|
}
|
|
|
|
try
|
|
{
|
|
var jobs = await _apiClient.GetPendingJobsAsync();
|
|
LogForm.Log($"Polling: znaleziono {jobs.Count} zleceń");
|
|
|
|
if (jobs.Count == 0)
|
|
{
|
|
_onStatusUpdate($"Brak zleceń (wydrukowano: {_totalPrinted})");
|
|
return;
|
|
}
|
|
|
|
int printed = 0;
|
|
int failed = 0;
|
|
|
|
string lastError = "";
|
|
foreach (var job in jobs)
|
|
{
|
|
try
|
|
{
|
|
LogForm.Log($"Job {job.Id}: pobieranie etykiety...");
|
|
var labelBytes = await _apiClient.DownloadLabelAsync(job.Id);
|
|
LogForm.Log($"Job {job.Id}: pobrano {labelBytes.Length} bajtów");
|
|
|
|
if (labelBytes.Length == 0)
|
|
{
|
|
failed++;
|
|
lastError = $"Job {job.Id}: pusty plik etykiety";
|
|
LogForm.Log($"BŁĄD: {lastError}");
|
|
continue;
|
|
}
|
|
|
|
LogForm.Log($"Job {job.Id}: drukowanie na '{_printerName}'...");
|
|
bool success = _printService.PrintPdf(labelBytes, _printerName);
|
|
|
|
if (success)
|
|
{
|
|
await _apiClient.MarkCompleteAsync(job.Id);
|
|
printed++;
|
|
_totalPrinted++;
|
|
LogForm.Log($"Job {job.Id}: wydrukowano i oznaczono jako complete ✓");
|
|
}
|
|
else
|
|
{
|
|
failed++;
|
|
lastError = $"Job {job.Id}: druk nie powiódł się";
|
|
LogForm.Log($"BŁĄD: {lastError}");
|
|
}
|
|
}
|
|
catch (HttpRequestException ex)
|
|
{
|
|
failed++;
|
|
lastError = $"Job {job.Id}: HTTP {ex.StatusCode} — {ex.Message}";
|
|
LogForm.Log($"BŁĄD: {lastError}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
failed++;
|
|
lastError = $"Job {job.Id}: {ex.GetType().Name} — {ex.Message}";
|
|
LogForm.Log($"BŁĄD: {lastError}");
|
|
}
|
|
}
|
|
|
|
if (failed > 0)
|
|
{
|
|
_onStatusUpdate($"Wydrukowano: {printed}, błędy: {failed} (łącznie: {_totalPrinted})");
|
|
}
|
|
else
|
|
{
|
|
_onStatusUpdate($"Wydrukowano {printed} etykiet (łącznie: {_totalPrinted})");
|
|
}
|
|
}
|
|
catch (HttpRequestException ex)
|
|
{
|
|
_onError($"API niedostępne: {ex.Message}");
|
|
}
|
|
catch (TaskCanceledException)
|
|
{
|
|
_onError("Timeout połączenia z API");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_onError(ex.Message);
|
|
}
|
|
finally
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_isProcessing = false;
|
|
}
|
|
}
|
|
}
|
|
}
|