Clean up. Almost ready to deploy maybe. REally wanna rewrite but hey eventually we will.
This commit is contained in:
131
src/lib/hooks/useSharedStatusSubscription.ts
Normal file
131
src/lib/hooks/useSharedStatusSubscription.ts
Normal file
@ -0,0 +1,131 @@
|
||||
'use client';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { createClient } from '@/utils/supabase';
|
||||
import type { RealtimeChannel } from '@supabase/supabase-js';
|
||||
|
||||
export type ConnectionStatus =
|
||||
| 'connecting'
|
||||
| 'connected'
|
||||
| 'disconnected'
|
||||
| 'updating';
|
||||
|
||||
// Singleton state
|
||||
let sharedChannel: RealtimeChannel | null = null;
|
||||
let sharedConnectionStatus: ConnectionStatus = 'disconnected';
|
||||
const subscribers = new Set<(status: ConnectionStatus) => void>();
|
||||
const statusUpdateCallbacks = new Set<() => void>();
|
||||
//const subscribers: Set<(status: ConnectionStatus) => void> = new Set();
|
||||
//const statusUpdateCallbacks: Set<() => void> = new Set();
|
||||
let reconnectAttempts = 0;
|
||||
let reconnectTimeout: NodeJS.Timeout | undefined;
|
||||
const supabase = createClient();
|
||||
|
||||
const notifySubscribers = (status: ConnectionStatus) => {
|
||||
sharedConnectionStatus = status;
|
||||
subscribers.forEach(callback => callback(status));
|
||||
};
|
||||
|
||||
const notifyStatusUpdate = () => {
|
||||
statusUpdateCallbacks.forEach(callback => callback());
|
||||
};
|
||||
|
||||
const cleanup = () => {
|
||||
if (reconnectTimeout) {
|
||||
clearTimeout(reconnectTimeout);
|
||||
reconnectTimeout = undefined;
|
||||
}
|
||||
|
||||
if (sharedChannel) {
|
||||
supabase.removeChannel(sharedChannel).catch((error) => {
|
||||
console.error('Error removing shared channel:', error);
|
||||
});
|
||||
sharedChannel = null;
|
||||
}
|
||||
};
|
||||
|
||||
const connect = () => {
|
||||
if (sharedChannel) return; // Already connected or connecting
|
||||
|
||||
cleanup();
|
||||
notifySubscribers('connecting');
|
||||
|
||||
const channel = supabase
|
||||
.channel('shared_status_updates', {
|
||||
config: { broadcast: {self: true }}
|
||||
})
|
||||
.on('broadcast', { event: 'status_updated' }, () => {
|
||||
notifyStatusUpdate();
|
||||
})
|
||||
.subscribe((status) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
||||
if (status === 'SUBSCRIBED') {
|
||||
notifySubscribers('connected');
|
||||
reconnectAttempts = 0;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
||||
} else if (status === 'CHANNEL_ERROR' || status === 'CLOSED') {
|
||||
notifySubscribers('disconnected');
|
||||
|
||||
if (reconnectAttempts < 5) {
|
||||
reconnectAttempts++;
|
||||
const delay = 2000 * reconnectAttempts;
|
||||
|
||||
reconnectTimeout = setTimeout(() => {
|
||||
if (subscribers.size > 0) { // Only reconnect if there are active subscribers
|
||||
connect();
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sharedChannel = channel;
|
||||
};
|
||||
|
||||
const disconnect = () => {
|
||||
cleanup();
|
||||
notifySubscribers('disconnected');
|
||||
};
|
||||
|
||||
export const useSharedStatusSubscription = (onStatusUpdate?: () => void) => {
|
||||
const [connectionStatus, setConnectionStatus] = useState<ConnectionStatus>(sharedConnectionStatus);
|
||||
|
||||
useEffect(() => {
|
||||
// Subscribe to status changes
|
||||
subscribers.add(setConnectionStatus);
|
||||
|
||||
// Subscribe to status updates
|
||||
if (onStatusUpdate) {
|
||||
statusUpdateCallbacks.add(onStatusUpdate);
|
||||
}
|
||||
|
||||
// Connect if this is the first subscriber
|
||||
if (subscribers.size === 1) {
|
||||
const timeout = setTimeout(connect, 1000);
|
||||
return () => clearTimeout(timeout);
|
||||
}
|
||||
|
||||
return () => {
|
||||
// Cleanup subscriptions
|
||||
subscribers.delete(setConnectionStatus);
|
||||
if (onStatusUpdate) {
|
||||
statusUpdateCallbacks.delete(onStatusUpdate);
|
||||
}
|
||||
|
||||
// Disconnect if no more subscribers
|
||||
if (subscribers.size === 0) {
|
||||
disconnect();
|
||||
}
|
||||
};
|
||||
}, [onStatusUpdate]);
|
||||
|
||||
const reconnect = useCallback(() => {
|
||||
reconnectAttempts = 0;
|
||||
connect();
|
||||
}, []);
|
||||
|
||||
return {
|
||||
connectionStatus,
|
||||
connect: reconnect,
|
||||
disconnect,
|
||||
};
|
||||
};
|
Reference in New Issue
Block a user