Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions content/wardrive.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ const state = {
capturedPingCoords: null, // { lat, lon, accuracy } captured at ping time, used for API post after 7s delay
devicePublicKey: null, // Hex string of device's public key (used for capacity check)
disconnectReason: null, // Tracks the reason for disconnection (e.g., "app_down", "capacity_full", "error", "normal")
pingInProgress: false, // Flag to track if a ping operation (including API post) is in progress
repeaterTracking: {
isListening: false, // Whether we're currently listening for echoes
sentTimestamp: null, // Timestamp when the ping was sent
Expand Down Expand Up @@ -425,8 +426,19 @@ function startCooldown() {
function updateControlsForCooldown() {
const connected = !!state.connection;
const inCooldown = isInCooldown();
sendPingBtn.disabled = !connected || inCooldown;
autoToggleBtn.disabled = !connected || inCooldown;
debugLog(`updateControlsForCooldown: connected=${connected}, inCooldown=${inCooldown}, pingInProgress=${state.pingInProgress}`);
sendPingBtn.disabled = !connected || inCooldown || state.pingInProgress;
autoToggleBtn.disabled = !connected || inCooldown || state.pingInProgress;
}

/**
* Helper function to unlock ping controls after ping operation completes
* @param {string} reason - Debug reason for unlocking controls
*/
function unlockPingControls(reason) {
state.pingInProgress = false;
updateControlsForCooldown();
debugLog(`Ping controls unlocked (pingInProgress=false) ${reason}`);
}

// Timer cleanup
Expand Down Expand Up @@ -461,6 +473,9 @@ function cleanupAllTimers() {
// Clear captured ping coordinates
state.capturedPingCoords = null;

// Clear ping in progress flag
state.pingInProgress = false;

// Clear device public key
state.devicePublicKey = null;
}
Expand Down Expand Up @@ -1190,6 +1205,9 @@ async function postApiAndRefreshMap(lat, lon, accuracy, heardRepeats) {
debugLog(`Skipping map refresh (accuracy ${accuracy}m exceeds threshold)`);
}

// Unlock ping controls now that API post is complete
unlockPingControls("after API post completion");

// Update status based on current mode
if (state.connection) {
if (state.running) {
Expand Down Expand Up @@ -1834,6 +1852,11 @@ async function sendPing(manual = false) {
// Both validations passed - execute ping operation (Mesh + API)
debugLog("All validations passed, executing ping operation");

// Lock ping controls for the entire ping lifecycle (until API post completes)
state.pingInProgress = true;
updateControlsForCooldown();
debugLog("Ping controls locked (pingInProgress=true)");

const payload = buildPayload(lat, lon);
debugLog(`Sending ping to channel: "${payload}"`);

Expand Down Expand Up @@ -1904,6 +1927,9 @@ async function sendPing(manual = false) {
// This should never happen as coordinates are always captured before ping
debugError(`CRITICAL: No captured ping coordinates available for API post - this indicates a logic error`);
debugError(`Skipping API post to avoid posting incorrect coordinates`);

// Unlock ping controls since API post is being skipped
unlockPingControls("after skipping API post due to missing coordinates");
}

// Clear captured coordinates after API post completes (always, regardless of path)
Expand All @@ -1919,6 +1945,9 @@ async function sendPing(manual = false) {
} catch (e) {
debugError(`Ping operation failed: ${e.message}`, e);
setStatus(e.message || "Ping failed", STATUS_COLORS.error);

// Unlock ping controls on error
unlockPingControls("after error");
}
}

Expand Down
4 changes: 4 additions & 0 deletions docs/CONNECTION_WORKFLOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,10 @@ stateDiagram-v2
### Auto-Ping Interactions
- **Manual during auto**: auto pauses, resumes after
- **7s cooldown**: prevents rapid-fire pings
- **Control locking**: "Send Ping" and "Start Auto Ping" buttons remain locked for entire ping lifecycle:
- Locked when: ping sent → listening for repeats (7s) → finalizing repeats → posting to API (3s + API time)
- Unlocked when: API post completes or error occurs
- Prevents starting new pings while previous ping is still processing
- **Page hidden**: auto stops, must restart manually
- **Cooldown bypass**: only on disconnect

Expand Down