added unsubscribe

This commit is contained in:
cpu
2025-03-26 21:15:47 +01:00
parent 3561db616c
commit bade9c0a15

164
app.js
View File

@@ -42,38 +42,144 @@ const cameraCancelButton = document.getElementById('cameraCancelButton');
let stream = null; let stream = null;
async function subscribeToPushNotifications() { async function subscribeToPushNotifications() {
if ('serviceWorker' in navigator && 'PushManager' in window) { let buttonId = BUTTON_ID;
try { // 1. Validate input buttonId
const registration = await navigator.serviceWorker.ready; if (!buttonId || typeof buttonId !== 'string' || buttonId.trim() === '') {
const subscription = await registration.pushManager.subscribe({ console.error('Button ID is required to subscribe.');
userVisibleOnly: true, alert('Please provide a valid Flic Button ID/Serial.');
applicationServerKey: urlBase64ToUint8Array(PUBLIC_VAPID_KEY) return;
});
// Send subscription to your server
await fetch(`${BACKEND_URL}/subscribe`, {
method: 'POST',
body: JSON.stringify({
button_id: BACKEND_URL,
subscription: subscription // The PushSubscription object
}),
headers: {
'Content-Type': 'application/json'
},
});
pushSubscription = subscription;
console.log('Push subscription successful');
} catch (error) {
console.error('Error subscribing to push:', error);
}
} }
}
function urlBase64ToUint8Array(base64String) { // 2. Check for browser support
if (!('serviceWorker' in navigator) || !('PushManager' in window)) {
console.error('Push Messaging is not supported');
alert('Sorry, Push Notifications are not supported by your browser.');
return;
}
try {
// 3. Request notification permission (requires user interaction)
const permission = await Notification.requestPermission();
if (permission !== 'granted') {
console.error('Notification permission not granted.');
alert('You denied notification permission. Please enable it in browser settings if you want to link the button.');
return;
}
console.log('Notification permission granted.');
// 4. Get Service Worker registration
const registration = await navigator.serviceWorker.ready;
console.log('Service Worker is ready.');
// 5. Get existing subscription
let existingSubscription = await registration.pushManager.getSubscription();
let needsResubscribe = false;
if (existingSubscription) {
console.log('Existing subscription found.');
// 6. Compare applicationServerKeys
const existingKeyArrayBuffer = existingSubscription.options.applicationServerKey;
if (!existingKeyArrayBuffer) {
console.warn("Existing subscription doesn't have an applicationServerKey.");
needsResubscribe = true; // Treat as needing resubscription
} else {
const existingKeyBase64 = arrayBufferToBase64(existingKeyArrayBuffer);
console.log('Existing VAPID Key (Base64):', existingKeyBase64);
console.log('Current VAPID Key (Base64): ', PUBLIC_VAPID_KEY);
if (existingKeyBase64 !== PUBLIC_VAPID_KEY) {
console.log('VAPID keys DO NOT match. Unsubscribing the old one.');
await existingSubscription.unsubscribe();
console.log('Successfully unsubscribed old subscription.');
existingSubscription = null; // Clear it so we subscribe anew below
needsResubscribe = true; // Explicitly flag for clarity
} else {
console.log('VAPID keys match. No need to resubscribe.');
needsResubscribe = false;
}
}
} else {
console.log('No existing subscription found.');
needsResubscribe = true; // No subscription exists, so we need one
}
// 7. Subscribe if needed (no existing sub or keys mismatched)
let finalSubscription = existingSubscription; // Use existing if keys matched
if (needsResubscribe || !finalSubscription) {
console.log('Attempting to subscribe with current VAPID key...');
const applicationServerKey = urlBase64ToUint8Array(PUBLIC_VAPID_KEY);
finalSubscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
});
console.log('New push subscription obtained:', finalSubscription);
}
// 8. Send the final subscription (new or validated existing) to your server
if (!finalSubscription) {
console.error("Failed to obtain a final subscription object.");
alert("Could not get subscription details. Please try again.");
return;
}
console.log(`Sending subscription for button "${buttonId}" to backend...`);
const response = await fetch(`${BACKEND_URL}/subscribe`, {
method: 'POST',
body: JSON.stringify({
button_id: buttonId,
subscription: finalSubscription
}),
headers: {
'Content-Type': 'application/json'
}
});
// 9. Handle the server response
if (response.ok) {
const result = await response.json();
console.log('Push subscription successfully sent to server:', result.message);
} else {
let errorMessage = `Server error: ${response.status}`;
try {
const errorResult = await response.json();
errorMessage = errorResult.message || errorMessage;
} catch (e) {
errorMessage = response.statusText || errorMessage;
}
console.error('Failed to send push subscription to server:', errorMessage);
alert(`Failed to save notification settings on server: ${errorMessage}`);
}
} catch (error) {
console.error('Error during push subscription process:', error);
// Handle potential errors from permission request, SW registration, get/unsubscribe/subscribe, or fetch network issues
if (error.name === 'InvalidStateError') {
alert(`Subscription failed: ${error.message}. Please try again or ensure no conflicting subscriptions exist.`);
} else {
alert(`An error occurred: ${error.message}`);
}
}
}
// Helper to convert ArrayBuffer to Base64 string (URL safe)
function arrayBufferToBase64(buffer) {
let binary = '';
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, ''); // Remove padding
}
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4); const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding) const base64 = (base64String + padding)
.replace(/-/g, '+') .replace(/\-/g, '+')
.replace(/_/g, '/'); .replace(/_/g, '/');
const rawData = window.atob(base64); const rawData = window.atob(base64);
@@ -83,7 +189,7 @@ async function subscribeToPushNotifications() {
outputArray[i] = rawData.charCodeAt(i); outputArray[i] = rawData.charCodeAt(i);
} }
return outputArray; return outputArray;
} }
// Add sound toggle button // Add sound toggle button
const createSoundToggleButton = () => { const createSoundToggleButton = () => {