Enhance command handling: implement monotonic ID for deduplication and improve acknowledgment process

This commit is contained in:
MayaTheShy
2026-03-22 01:29:16 -04:00
parent c47ec63e50
commit a5e6be7f4b

View File

@@ -49,6 +49,7 @@ if (lastUpdate > 0) {
// Pending commands for bridge HTTP polling (fallback) // Pending commands for bridge HTTP polling (fallback)
let pendingCommands = []; let pendingCommands = [];
let nextCommandId = 1; // Monotonic ID for deduplication
// ========== Helpers ========== // ========== Helpers ==========
@@ -70,9 +71,10 @@ function pushCommandToBridge(command) {
} }
} }
if (!sent) { if (!sent) {
// Fallback: queue for HTTP polling // Fallback: queue for HTTP polling with monotonic ID
pendingCommands.push({ ...command, timestamp: Date.now() }); const id = nextCommandId++;
console.log(`[Bridge] Queued command via HTTP poll (no WS bridge)`); pendingCommands.push({ ...command, id, timestamp: Date.now() });
console.log(`[Bridge] Queued command #${id} via HTTP poll (no WS bridge)`);
} }
} }
@@ -413,12 +415,24 @@ app.get('/api/bridge/commands', (req, res) => {
} }
}); });
// Bridge acknowledges commands // Bridge acknowledges commands by last processed ID
// Only removes commands with id <= lastProcessedId, preventing
// race conditions where new commands arrive between GET and ACK.
app.post('/api/bridge/commands/ack', (req, res) => { app.post('/api/bridge/commands/ack', (req, res) => {
try { try {
const cleared = pendingCommands.length; const { lastProcessedId } = req.body || {};
pendingCommands = []; if (lastProcessedId !== undefined && lastProcessedId !== null) {
res.json({ success: true, cleared }); // Remove only commands that have been processed
const before = pendingCommands.length;
pendingCommands = pendingCommands.filter(cmd => (cmd.id || 0) > lastProcessedId);
const cleared = before - pendingCommands.length;
res.json({ success: true, cleared });
} else {
// Legacy: clear all (backwards-compatible)
const cleared = pendingCommands.length;
pendingCommands = [];
res.json({ success: true, cleared });
}
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message }); res.status(500).json({ error: error.message });
} }