- 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.
269 lines
7.5 KiB
TypeScript
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
|
|
}
|
|
}
|