feat(client): pausar/continuar envio com auto-retomada após 10 min

- Checkbox "Pausar Envio de Imagens" na bandeja (tray)
- Auto-retomada automática após 10 min de pausa (caso usuário esqueça)
- client-monitor: comandos IPC pause/resume; processQueue e executarSincronizacaoLocal
  respeitam a pausa, mantendo imagens na fila sem perdê-las
- Estado de pausa reaplicado se o monitor reiniciar
- "Forçar Sincronização" retoma o envio automaticamente se estiver pausado
- Bump 1.2.7 → 1.2.8

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
VPS 4 Builder
2026-05-31 02:57:43 +02:00
parent bfcf84c5ac
commit 3c6b62126e
3 changed files with 83 additions and 8 deletions
+17 -4
View File
@@ -1128,8 +1128,12 @@ async function executarSincronizacaoLocal() {
let processadas = 0; let processadas = 0;
for (const file of imagens) { for (const file of imagens) {
if (isSendingPaused) {
addLog(`⏸️ Envio pausado durante a sincronização — interrompendo. ${processadas} já processadas.`);
break;
}
const filePath = path.join(pastaImagensSensor, file); const filePath = path.join(pastaImagensSensor, file);
const stat = fs.statSync(filePath); const stat = fs.statSync(filePath);
if (stat.isDirectory()) { if (stat.isDirectory()) {
continue; continue;
@@ -1156,12 +1160,17 @@ async function executarSincronizacaoLocal() {
// Fila para processar uploads de forma sequencial // Fila para processar uploads de forma sequencial
const uploadQueue = []; const uploadQueue = [];
let isProcessingQueue = false; let isProcessingQueue = false;
let isSendingPaused = false; // Controle de pausa/continuação do envio
async function processQueue() { async function processQueue() {
if (isProcessingQueue) return; if (isProcessingQueue) return;
if (isSendingPaused) {
addLog(`⏸️ Envio pausado — ${uploadQueue.length} imagem(ns) aguardando na fila.`);
return;
}
isProcessingQueue = true; isProcessingQueue = true;
while (uploadQueue.length > 0) { while (uploadQueue.length > 0 && !isSendingPaused) {
const item = uploadQueue.shift(); const item = uploadQueue.shift();
const nextPath = item.filePath; const nextPath = item.filePath;
const isBacklog = item.isBacklog; const isBacklog = item.isBacklog;
@@ -1171,8 +1180,12 @@ async function processQueue() {
addLog(`⚠️ Falha ao processar upload de ${path.basename(nextPath)}: ${e.message}`); addLog(`⚠️ Falha ao processar upload de ${path.basename(nextPath)}: ${e.message}`);
} }
} }
isProcessingQueue = false; isProcessingQueue = false;
if (isSendingPaused && uploadQueue.length > 0) {
addLog(`⏸️ Envio pausado — ${uploadQueue.length} imagem(ns) permanecem na fila.`);
}
} }
// Função de Monitoramento da Pasta de Imagens (Chokidar) // Função de Monitoramento da Pasta de Imagens (Chokidar)
+65 -3
View File
@@ -11,6 +11,54 @@ let currentStatus = { connected: false, identified: false };
let downloadProgress = null; // Variável para controlar o progresso de download let downloadProgress = null; // Variável para controlar o progresso de download
const recentLogs = []; const recentLogs = [];
// ================================================================
// CONTROLE DE PAUSA DE ENVIO
// ================================================================
let isSendingPaused = false; // true = envio de imagens pausado
let autoResumeTimer = null; // timer que retoma o envio sozinho
const AUTO_RESUME_MS = 10 * 60 * 1000; // 10 minutos
function pauseSending() {
isSendingPaused = true;
if (monitorProcess) monitorProcess.send({ command: 'pause' });
// Agenda retomada automática após 10 min, caso o usuário esqueça de continuar
if (autoResumeTimer) clearTimeout(autoResumeTimer);
autoResumeTimer = setTimeout(() => {
addLog('▶️ Auto-retomada: 10 minutos se passaram, retomando envio automaticamente.');
resumeSending(true);
}, AUTO_RESUME_MS);
if (tray) {
tray.displayBalloon({
title: 'ScoreOdonto - Envio Pausado',
content: 'O envio de imagens foi pausado. Ele será retomado automaticamente em 10 minutos se você não continuar antes.',
iconType: 'warning'
});
}
updateTrayMenu();
}
function resumeSending(isAuto = false) {
isSendingPaused = false;
if (autoResumeTimer) { clearTimeout(autoResumeTimer); autoResumeTimer = null; }
if (monitorProcess) monitorProcess.send({ command: 'resume' });
if (tray && !isAuto) {
tray.displayBalloon({
title: 'ScoreOdonto - Envio Retomado',
content: 'O envio de imagens foi retomado.',
iconType: 'info'
});
}
updateTrayMenu();
}
function toggleSending() {
if (isSendingPaused) resumeSending(false);
else pauseSending();
}
// ================================================================ // ================================================================
// AUTO-UPDATER CONFIG // AUTO-UPDATER CONFIG
// ================================================================ // ================================================================
@@ -255,15 +303,29 @@ function updateTrayMenu(countdown = null, countdownInterval = null, updateVersio
} }
template.push( template.push(
{ {
label: 'Forçar Sincronização 🔄', label: isSendingPaused ? '⏸️ Envio PAUSADO (retoma em ~10 min)' : '▶️ Envio Ativo',
enabled: false
},
{
label: 'Pausar Envio de Imagens',
type: 'checkbox',
checked: isSendingPaused,
click: () => toggleSending()
},
{ type: 'separator' },
{
label: 'Forçar Sincronização 🔄',
click: () => { click: () => {
if (isSendingPaused) {
resumeSending(false);
}
if (monitorProcess) { if (monitorProcess) {
monitorProcess.send({ command: 'sync' }); monitorProcess.send({ command: 'sync' });
} else { } else {
startMonitorProcess(); startMonitorProcess();
} }
} }
}, },
{ {
label: 'Verificar Atualizações 🔄', label: 'Verificar Atualizações 🔄',
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "rx.scoreodonto.com-client", "name": "rx.scoreodonto.com-client",
"version": "1.2.7", "version": "1.2.8",
"author": "ScoreOdonto", "author": "ScoreOdonto",
"description": "Cliente Windows para envio de imagens dentais da ScoreOdonto", "description": "Cliente Windows para envio de imagens dentais da ScoreOdonto",
"main": "index.js", "main": "index.js",