Add automatic token refresh for browser phone to prevent timeouts

- Implement proactive token refresh 5 minutes before expiry (1-hour tokens)
- Add call-safe refresh logic that postpones refresh during active calls
- Replace fixed-interval refresh with smart scheduling based on token expiry
- Add proper cleanup on page unload to prevent memory leaks
- Enhance error handling with retry mechanisms for network failures
- Apply to both admin browser phone page and frontend shortcode

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-08-14 12:01:05 -07:00
parent 8c78e0cb11
commit 2cb9b9472d
2 changed files with 165 additions and 4 deletions

View File

@@ -5691,6 +5691,8 @@ class TWP_Admin {
var currentCall = null;
var callTimer = null;
var callStartTime = null;
var tokenRefreshTimer = null;
var tokenExpiry = null;
// Wait for SDK to load
function waitForTwilioSDK(callback) {
@@ -5718,6 +5720,9 @@ class TWP_Admin {
if (response.success) {
$('#browser-phone-error').hide();
setupTwilioDevice(response.data.token);
// Set token expiry and schedule refresh
tokenExpiry = Date.now() + (response.data.expires_in || 3600) * 1000;
scheduleTokenRefresh();
} else {
// WordPress wp_send_json_error sends the error message as response.data
var errorMsg = response.data || response.error || 'Unknown error';
@@ -5852,18 +5857,65 @@ class TWP_Admin {
}
function refreshToken() {
console.log('Refreshing capability token...');
// Don't refresh if currently in a call
if (currentCall) {
console.log('Currently in call, postponing token refresh');
setTimeout(refreshToken, 60000); // Retry in 1 minute
return;
}
$.post(ajaxurl, {
action: 'twp_generate_capability_token',
nonce: '<?php echo wp_create_nonce('twp_ajax_nonce'); ?>'
}, function(response) {
if (response.success && device) {
console.log('Token refreshed successfully');
device.updateToken(response.data.token);
// Update token expiry and schedule next refresh
tokenExpiry = Date.now() + (response.data.expires_in || 3600) * 1000;
scheduleTokenRefresh();
} else {
console.error('Failed to refresh token:', response.data);
showError('Failed to refresh connection. Please refresh the page.');
}
}).fail(function() {
console.error('Failed to refresh token');
console.error('Failed to refresh token - network error');
// Retry in 30 seconds
setTimeout(refreshToken, 30000);
});
}
/**
* Schedule token refresh
* Refreshes token 5 minutes before expiry
*/
function scheduleTokenRefresh() {
// Clear any existing timer
if (tokenRefreshTimer) {
clearTimeout(tokenRefreshTimer);
}
if (!tokenExpiry) {
console.error('Token expiry time not set');
return;
}
// Calculate time until refresh (5 minutes before expiry)
var refreshBuffer = 5 * 60 * 1000; // 5 minutes in milliseconds
var timeUntilRefresh = tokenExpiry - Date.now() - refreshBuffer;
if (timeUntilRefresh <= 0) {
// Token needs refresh immediately
refreshToken();
} else {
// Schedule refresh
console.log('Scheduling token refresh in', Math.round(timeUntilRefresh / 1000), 'seconds');
tokenRefreshTimer = setTimeout(refreshToken, timeUntilRefresh);
}
}
function showError(message) {
$('#browser-phone-error').html('<p><strong>Error:</strong> ' + message + '</p>').show();
$('#phone-status').text('Error').css('color', '#f44336');
@@ -6005,8 +6057,15 @@ class TWP_Admin {
}, 1000);
});
// Refresh token every 50 minutes (tokens expire in 1 hour)
setInterval(initializeBrowserPhone, 50 * 60 * 1000);
// Clean up on page unload
$(window).on('beforeunload', function() {
if (tokenRefreshTimer) {
clearTimeout(tokenRefreshTimer);
}
if (device) {
device.destroy();
}
});
// Mode switching functionality
$('input[name="call_mode"]').on('change', function() {