web-app/src/composables/useRelayHub.ts
padreug 36e9694c1b feat: Enhance RelayHub component with subscription count details (still not working)
- Update RelayHubStatus.vue to display both local and global subscription counts, improving user visibility into active subscriptions.
- Add totalSubscriptionCount computed property in useRelayHub.ts to track the total number of subscriptions.
- Implement totalSubscriptionCount getter in relayHub.ts to return the size of the subscriptions map.
- Include debug logging in relayHub.ts for connected relay counts and statuses to aid in troubleshooting.
2025-08-10 18:19:18 +02:00

269 lines
7.5 KiB
TypeScript

import { ref, computed, onMounted, onUnmounted } from 'vue'
import { relayHub, type SubscriptionConfig, type RelayStatus } from '../lib/nostr/relayHub'
import { config } from '../lib/config'
export function useRelayHub() {
// Reactive state
const isConnected = ref(false)
const connectionStatus = ref<'connecting' | 'connected' | 'disconnected' | 'error'>('disconnected')
const relayStatuses = ref<RelayStatus[]>([])
const error = ref<Error | null>(null)
const activeSubscriptions = ref<Set<string>>(new Set())
// Computed properties
const connectedRelayCount = computed(() => relayHub.connectedRelayCount)
const totalRelayCount = computed(() => relayHub.totalRelayCount)
const totalSubscriptionCount = computed(() => relayHub.totalSubscriptionCount)
const connectionHealth = computed(() => {
if (totalRelayCount.value === 0) return 0
return (connectedRelayCount.value / totalRelayCount.value) * 100
})
// Initialize relay hub
const initialize = async (): Promise<void> => {
try {
connectionStatus.value = 'connecting'
error.value = null
// Get relay URLs from config
const relayUrls = config.nostr.relays
if (!relayUrls || relayUrls.length === 0) {
throw new Error('No relay URLs configured')
}
// Initialize the relay hub
await relayHub.initialize(relayUrls)
// Set up event listeners
setupEventListeners()
connectionStatus.value = 'connected'
isConnected.value = true
console.log('RelayHub initialized successfully')
} catch (err) {
const errorObj = err instanceof Error ? err : new Error('Failed to initialize RelayHub')
error.value = errorObj
connectionStatus.value = 'error'
isConnected.value = false
console.error('Failed to initialize RelayHub:', errorObj)
throw errorObj
}
}
// Connect to relays
const connect = async (): Promise<void> => {
try {
if (!relayHub.isInitialized) {
await initialize()
return
}
connectionStatus.value = 'connecting'
error.value = null
await relayHub.connect()
connectionStatus.value = 'connected'
isConnected.value = true
} catch (err) {
const errorObj = err instanceof Error ? err : new Error('Failed to connect')
error.value = errorObj
connectionStatus.value = 'error'
isConnected.value = false
throw errorObj
}
}
// Disconnect from relays
const disconnect = (): void => {
relayHub.disconnect()
connectionStatus.value = 'disconnected'
isConnected.value = false
error.value = null
}
// Subscribe to events
const subscribe = (config: SubscriptionConfig): (() => void) => {
try {
const unsubscribe = relayHub.subscribe(config)
activeSubscriptions.value.add(config.id)
// Return enhanced unsubscribe function
return () => {
unsubscribe()
activeSubscriptions.value.delete(config.id)
}
} catch (err) {
const errorObj = err instanceof Error ? err : new Error('Failed to subscribe')
error.value = errorObj
throw errorObj
}
}
// Publish an event
const publishEvent = async (event: any): Promise<{ success: number; total: number }> => {
try {
return await relayHub.publishEvent(event)
} catch (err) {
const errorObj = err instanceof Error ? err : new Error('Failed to publish event')
error.value = errorObj
throw errorObj
}
}
// Query events (one-time fetch)
const queryEvents = async (filters: any[], relays?: string[]): Promise<any[]> => {
try {
return await relayHub.queryEvents(filters, relays)
} catch (err) {
const errorObj = err instanceof Error ? err : new Error('Failed to query events')
error.value = errorObj
throw errorObj
}
}
// Force reconnection
const reconnect = async (): Promise<void> => {
try {
connectionStatus.value = 'connecting'
error.value = null
await relayHub.reconnect()
connectionStatus.value = 'connected'
isConnected.value = true
} catch (err) {
const errorObj = err instanceof Error ? err : new Error('Failed to reconnect')
error.value = errorObj
connectionStatus.value = 'error'
isConnected.value = false
throw errorObj
}
}
// Get relay status
const getRelayStatus = (url: string): RelayStatus | undefined => {
return relayStatuses.value.find(status => status.url === url)
}
// Check if a specific relay is connected
const isRelayConnected = (url: string): boolean => {
return relayHub.isRelayConnected(url)
}
// Setup event listeners for the relay hub
const setupEventListeners = (): void => {
// Connection events
relayHub.on('connected', (count: number) => {
console.log(`Connected to ${count} relays`)
isConnected.value = true
connectionStatus.value = 'connected'
error.value = null
})
relayHub.on('disconnected', () => {
console.log('Disconnected from all relays')
isConnected.value = false
connectionStatus.value = 'disconnected'
})
relayHub.on('connectionError', (err: Error) => {
console.error('Connection error:', err)
error.value = err
connectionStatus.value = 'error'
isConnected.value = false
})
relayHub.on('allRelaysDisconnected', () => {
console.warn('All relays disconnected')
isConnected.value = false
connectionStatus.value = 'disconnected'
})
relayHub.on('partialDisconnection', ({ connected, total }: { connected: number; total: number }) => {
console.warn(`Partial disconnection: ${connected}/${total} relays connected`)
isConnected.value = connected > 0
connectionStatus.value = connected > 0 ? 'connected' : 'disconnected'
})
relayHub.on('maxReconnectAttemptsReached', () => {
console.error('Max reconnection attempts reached')
connectionStatus.value = 'error'
isConnected.value = false
error.value = new Error('Max reconnection attempts reached')
})
relayHub.on('networkOffline', () => {
console.log('Network went offline')
connectionStatus.value = 'disconnected'
isConnected.value = false
})
// Update relay statuses periodically
const updateRelayStatuses = () => {
relayStatuses.value = relayHub.relayStatuses
}
// Update immediately and then every 10 seconds
updateRelayStatuses()
const statusInterval = setInterval(updateRelayStatuses, 10000)
// Cleanup interval on unmount
onUnmounted(() => {
clearInterval(statusInterval)
})
}
// Cleanup function
const cleanup = (): void => {
// Close all active subscriptions
activeSubscriptions.value.forEach(subId => {
relayHub.unsubscribe(subId)
})
activeSubscriptions.value.clear()
}
// Auto-initialize on mount if config is available
onMounted(async () => {
try {
if (config.nostr.relays && config.nostr.relays.length > 0) {
await initialize()
}
} catch (err) {
console.warn('Auto-initialization failed:', err)
}
})
// Cleanup on unmount
onUnmounted(() => {
cleanup()
})
return {
// State
isConnected,
connectionStatus,
relayStatuses,
error,
activeSubscriptions,
// Computed
connectedRelayCount,
totalRelayCount,
totalSubscriptionCount,
connectionHealth,
// Methods
initialize,
connect,
disconnect,
subscribe,
publishEvent,
queryEvents,
reconnect,
getRelayStatus,
isRelayConnected,
cleanup
}
}