feat: Integrate Relay Hub for centralized Nostr connection management
- Introduce a new composable, useRelayHub, to manage all Nostr WebSocket connections, enhancing connection stability and performance. - Update existing components and composables to utilize the Relay Hub for connecting, publishing events, and subscribing to updates, streamlining the overall architecture. - Add a RelayHubStatus component to display connection status and health metrics, improving user feedback on the connection state. - Implement a RelayHubDemo page to showcase the functionality of the Relay Hub, including connection tests and subscription management. - Ensure proper error handling and logging throughout the integration process to facilitate debugging and user experience.
This commit is contained in:
parent
df7e461c91
commit
7d7bee8e77
14 changed files with 1982 additions and 955 deletions
|
|
@ -1,9 +1,10 @@
|
|||
import { ref, computed, readonly } from 'vue'
|
||||
|
||||
import { SimplePool, nip04, finalizeEvent, type EventTemplate } from 'nostr-tools'
|
||||
import { nip04, finalizeEvent, type EventTemplate } from 'nostr-tools'
|
||||
import { hexToBytes } from '@/lib/utils/crypto'
|
||||
import { getAuthToken } from '@/lib/config/lnbits'
|
||||
import { config } from '@/lib/config'
|
||||
import { useRelayHub } from './useRelayHub'
|
||||
|
||||
// Types
|
||||
export interface ChatMessage {
|
||||
|
|
@ -63,14 +64,14 @@ const saveUnreadData = (peerPubkey: string, data: UnreadMessageData): void => {
|
|||
}
|
||||
|
||||
export function useNostrChat() {
|
||||
// Use the centralized relay hub
|
||||
const relayHub = useRelayHub()
|
||||
|
||||
// State
|
||||
const isConnected = ref(false)
|
||||
const messages = ref<Map<string, ChatMessage[]>>(new Map())
|
||||
const currentUser = ref<{ pubkey: string; prvkey: string } | null>(null)
|
||||
const processedMessageIds = ref(new Set<string>())
|
||||
const onMessageAdded = ref<((peerPubkey: string) => void) | null>(null)
|
||||
const pool = ref<SimplePool | null>(null)
|
||||
|
||||
// Reactive unread counts
|
||||
const unreadCounts = ref<Map<string, number>>(new Map())
|
||||
|
|
@ -81,7 +82,8 @@ export function useNostrChat() {
|
|||
// Store peers globally
|
||||
const peers = ref<any[]>([])
|
||||
|
||||
// Computed
|
||||
// Computed - use relay hub's connection status
|
||||
const isConnected = computed(() => relayHub.isConnected.value)
|
||||
const isLoggedIn = computed(() => !!currentUser.value)
|
||||
|
||||
// Get unread count for a peer
|
||||
|
|
@ -103,15 +105,6 @@ export function useNostrChat() {
|
|||
return total
|
||||
}
|
||||
|
||||
// Reactive computed total unread count
|
||||
const totalUnreadCount = computed(() => {
|
||||
let total = 0
|
||||
for (const count of unreadCounts.value.values()) {
|
||||
total += count
|
||||
}
|
||||
return total
|
||||
})
|
||||
|
||||
// Get latest message timestamp for a peer
|
||||
const getLatestMessageTimestamp = (peerPubkey: string): number => {
|
||||
return latestMessageTimestamps.value.get(peerPubkey) || 0
|
||||
|
|
@ -124,238 +117,163 @@ export function useNostrChat() {
|
|||
|
||||
// Update latest message timestamp for a peer
|
||||
const updateLatestMessageTimestamp = (peerPubkey: string, timestamp: number): void => {
|
||||
const currentLatest = latestMessageTimestamps.value.get(peerPubkey) || 0
|
||||
if (timestamp > currentLatest) {
|
||||
const current = latestMessageTimestamps.value.get(peerPubkey) || 0
|
||||
if (timestamp > current) {
|
||||
latestMessageTimestamps.value.set(peerPubkey, timestamp)
|
||||
// Force reactivity
|
||||
latestMessageTimestamps.value = new Map(latestMessageTimestamps.value)
|
||||
}
|
||||
}
|
||||
|
||||
// Update unread count for a peer
|
||||
const updateUnreadCount = (peerPubkey: string, count: number): void => {
|
||||
if (count > 0) {
|
||||
unreadCounts.value.set(peerPubkey, count)
|
||||
} else {
|
||||
unreadCounts.value.delete(peerPubkey)
|
||||
}
|
||||
// Force reactivity
|
||||
unreadCounts.value = new Map(unreadCounts.value)
|
||||
const current = unreadCounts.value.get(peerPubkey) || 0
|
||||
unreadCounts.value.set(peerPubkey, current + count)
|
||||
|
||||
// Save to localStorage
|
||||
const unreadData = getUnreadData(peerPubkey)
|
||||
unreadData.unreadCount = current + count
|
||||
saveUnreadData(peerPubkey, unreadData)
|
||||
}
|
||||
|
||||
// Mark messages as read for a peer
|
||||
const markMessagesAsRead = (peerPubkey: string): void => {
|
||||
const currentTimestamp = Math.floor(Date.now() / 1000)
|
||||
|
||||
// Update last read timestamp, reset unread count, and clear processed message IDs
|
||||
const updatedData: UnreadMessageData = {
|
||||
lastReadTimestamp: currentTimestamp,
|
||||
unreadCount: 0,
|
||||
processedMessageIds: new Set() // Clear processed messages when marking as read
|
||||
const current = unreadCounts.value.get(peerPubkey) || 0
|
||||
if (current > 0) {
|
||||
unreadCounts.value.set(peerPubkey, 0)
|
||||
|
||||
// Save to localStorage
|
||||
const unreadData = getUnreadData(peerPubkey)
|
||||
unreadData.unreadCount = 0
|
||||
unreadData.lastReadTimestamp = Date.now()
|
||||
saveUnreadData(peerPubkey, unreadData)
|
||||
}
|
||||
|
||||
saveUnreadData(peerPubkey, updatedData)
|
||||
updateUnreadCount(peerPubkey, 0)
|
||||
}
|
||||
|
||||
// Load unread counts from localStorage
|
||||
const loadUnreadCounts = (): void => {
|
||||
try {
|
||||
const keys = Object.keys(localStorage).filter(key =>
|
||||
key.startsWith(`${UNREAD_MESSAGES_KEY}-`)
|
||||
)
|
||||
|
||||
console.log('Loading unread counts from localStorage. Found keys:', keys)
|
||||
|
||||
for (const key of keys) {
|
||||
const peerPubkey = key.replace(`${UNREAD_MESSAGES_KEY}-`, '')
|
||||
const unreadData = getUnreadData(peerPubkey)
|
||||
console.log(`Peer ${peerPubkey}:`, {
|
||||
lastReadTimestamp: unreadData.lastReadTimestamp,
|
||||
unreadCount: unreadData.unreadCount,
|
||||
processedMessageIdsCount: unreadData.processedMessageIds.size
|
||||
})
|
||||
|
||||
if (unreadData.unreadCount > 0) {
|
||||
unreadCounts.value.set(peerPubkey, unreadData.unreadCount)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Failed to load unread counts from localStorage:', error)
|
||||
}
|
||||
}
|
||||
// const loadUnreadCounts = (): void => {
|
||||
// try {
|
||||
// // Load unread counts for all peers we have messages for
|
||||
// for (const [peerPubkey] of messages.value) {
|
||||
// const unreadData = getUnreadData(peerPubkey)
|
||||
// if (unreadData.unreadCount > 0) {
|
||||
// unreadCounts.value.set(peerPubkey, unreadData.unreadCount)
|
||||
// }
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.warn('Failed to load unread counts:', error)
|
||||
// }
|
||||
// }
|
||||
|
||||
// Initialize unread counts on startup
|
||||
loadUnreadCounts()
|
||||
// Clear unread count for a peer
|
||||
// const clearUnreadCount = (peerPubkey: string): void => {
|
||||
// unreadCounts.value.delete(peerPubkey)
|
||||
//
|
||||
// // Clear from localStorage
|
||||
// const unreadData = getUnreadData(peerPubkey)
|
||||
// unreadData.unreadCount = 0
|
||||
// saveUnreadData(peerPubkey, unreadData)
|
||||
// }
|
||||
|
||||
// Clear all unread counts (for testing)
|
||||
// Clear all unread counts
|
||||
const clearAllUnreadCounts = (): void => {
|
||||
unreadCounts.value.clear()
|
||||
unreadCounts.value = new Map(unreadCounts.value)
|
||||
|
||||
// Also clear from localStorage
|
||||
try {
|
||||
const keys = Object.keys(localStorage).filter(key =>
|
||||
key.startsWith(`${UNREAD_MESSAGES_KEY}-`)
|
||||
)
|
||||
|
||||
for (const key of keys) {
|
||||
localStorage.removeItem(key)
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Failed to clear unread counts from localStorage:', error)
|
||||
// Clear from localStorage for all peers
|
||||
for (const [peerPubkey] of messages.value) {
|
||||
const unreadData = getUnreadData(peerPubkey)
|
||||
unreadData.unreadCount = 0
|
||||
saveUnreadData(peerPubkey, unreadData)
|
||||
}
|
||||
}
|
||||
|
||||
// Clear processed message IDs for a specific peer (useful for debugging)
|
||||
// Clear processed message IDs for a peer
|
||||
const clearProcessedMessageIds = (peerPubkey: string): void => {
|
||||
try {
|
||||
const unreadData = getUnreadData(peerPubkey)
|
||||
const updatedData: UnreadMessageData = {
|
||||
...unreadData,
|
||||
processedMessageIds: new Set()
|
||||
}
|
||||
saveUnreadData(peerPubkey, updatedData)
|
||||
console.log(`Cleared processed message IDs for peer: ${peerPubkey}`)
|
||||
} catch (error) {
|
||||
console.warn('Failed to clear processed message IDs for peer:', peerPubkey, error)
|
||||
}
|
||||
const unreadData = getUnreadData(peerPubkey)
|
||||
unreadData.processedMessageIds.clear()
|
||||
saveUnreadData(peerPubkey, unreadData)
|
||||
}
|
||||
|
||||
// Debug function to show current state of unread data for a peer
|
||||
// Debug unread data for a peer
|
||||
const debugUnreadData = (peerPubkey: string): void => {
|
||||
try {
|
||||
const unreadData = getUnreadData(peerPubkey)
|
||||
console.log(`Debug unread data for ${peerPubkey}:`, {
|
||||
lastReadTimestamp: unreadData.lastReadTimestamp,
|
||||
unreadCount: unreadData.unreadCount,
|
||||
processedMessageIds: Array.from(unreadData.processedMessageIds),
|
||||
processedMessageIdsCount: unreadData.processedMessageIds.size
|
||||
})
|
||||
} catch (error) {
|
||||
console.warn('Failed to debug unread data for peer:', peerPubkey, error)
|
||||
}
|
||||
const unreadData = getUnreadData(peerPubkey)
|
||||
console.log(`Unread data for ${peerPubkey}:`, unreadData)
|
||||
}
|
||||
|
||||
// Get relays from config - requires VITE_NOSTR_RELAYS to be set
|
||||
// Get relay configuration
|
||||
const getRelays = (): NostrRelayConfig[] => {
|
||||
const configuredRelays = config.nostr.relays
|
||||
if (!configuredRelays || configuredRelays.length === 0) {
|
||||
throw new Error('VITE_NOSTR_RELAYS environment variable must be configured for chat functionality')
|
||||
}
|
||||
|
||||
return configuredRelays.map((url: string) => ({ url, read: true, write: true }))
|
||||
return config.nostr.relays.map(url => ({
|
||||
url,
|
||||
read: true,
|
||||
write: true
|
||||
}))
|
||||
}
|
||||
|
||||
// Initialize Nostr pool
|
||||
const initializePool = () => {
|
||||
if (!pool.value) {
|
||||
pool.value = new SimplePool()
|
||||
}
|
||||
}
|
||||
|
||||
// Connect to relays
|
||||
const connectToRelay = async (url: string): Promise<any> => {
|
||||
try {
|
||||
initializePool()
|
||||
const relay = pool.value!.ensureRelay(url)
|
||||
console.log(`Connected to relay: ${url}`)
|
||||
return relay
|
||||
} catch (error) {
|
||||
console.error(`Failed to connect to ${url}:`, error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// Connect to all relays
|
||||
// Connect using the relay hub
|
||||
const connect = async () => {
|
||||
try {
|
||||
// Get current user from LNBits
|
||||
await loadCurrentUser()
|
||||
|
||||
if (!currentUser.value) {
|
||||
console.warn('No user logged in - chat functionality will be limited')
|
||||
// Don't throw error, just continue without user data
|
||||
// The chat will still work for viewing messages, but sending will fail
|
||||
// The relay hub should already be initialized by the app
|
||||
if (!relayHub.isConnected.value) {
|
||||
await relayHub.connect()
|
||||
}
|
||||
|
||||
// Initialize pool
|
||||
initializePool()
|
||||
|
||||
// Connect to relays
|
||||
const relayConfigs = getRelays()
|
||||
const relays = await Promise.all(
|
||||
relayConfigs.map(relay => connectToRelay(relay.url))
|
||||
)
|
||||
|
||||
const connectedRelays = relays.filter(relay => relay !== null)
|
||||
isConnected.value = connectedRelays.length > 0
|
||||
|
||||
console.log(`Connected to ${connectedRelays.length} relays`)
|
||||
console.log('Connected to relays via RelayHub')
|
||||
} catch (error) {
|
||||
console.error('Failed to connect:', error)
|
||||
// Don't throw error, just log it and continue
|
||||
// This allows the chat to still work for viewing messages
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect from relays
|
||||
const disconnect = () => {
|
||||
if (pool.value) {
|
||||
const relayConfigs = getRelays()
|
||||
pool.value.close(relayConfigs.map(r => r.url))
|
||||
pool.value = null
|
||||
}
|
||||
isConnected.value = false
|
||||
messages.value.clear()
|
||||
processedMessageIds.value.clear()
|
||||
}
|
||||
|
||||
// Load current user from LNBits
|
||||
const loadCurrentUser = async () => {
|
||||
try {
|
||||
// Get current user from LNBits API using the auth endpoint
|
||||
const authToken = getAuthToken()
|
||||
if (!authToken) {
|
||||
throw new Error('No authentication token found')
|
||||
}
|
||||
|
||||
const API_BASE_URL = config.api.baseUrl || 'http://localhost:5006'
|
||||
const response = await fetch(`${API_BASE_URL}/api/v1/auth/nostr/me`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
console.log('API Response status:', response.status)
|
||||
console.log('API Response headers:', response.headers)
|
||||
|
||||
const responseText = await response.text()
|
||||
console.log('API Response text:', responseText)
|
||||
|
||||
if (response.ok) {
|
||||
try {
|
||||
const user = JSON.parse(responseText)
|
||||
currentUser.value = {
|
||||
pubkey: user.pubkey,
|
||||
prvkey: user.prvkey
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error('JSON Parse Error:', parseError)
|
||||
console.error('Response was:', responseText)
|
||||
throw new Error('Invalid JSON response from API')
|
||||
}
|
||||
} else {
|
||||
console.error('API Error:', response.status, responseText)
|
||||
throw new Error(`Failed to load current user: ${response.status}`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load current user:', error)
|
||||
console.error('Failed to connect to relays:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect using the relay hub
|
||||
const disconnect = () => {
|
||||
// Note: We don't disconnect the relay hub here as other components might be using it
|
||||
// The relay hub will be managed at the app level
|
||||
console.log('Chat disconnected from relays (relay hub remains active)')
|
||||
}
|
||||
|
||||
// Load current user from LNBits
|
||||
// const loadCurrentUser = async () => {
|
||||
// try {
|
||||
// // Get current user from LNBits API using the auth endpoint
|
||||
// const authToken = getAuthToken()
|
||||
// if (!authToken) {
|
||||
// throw new Error('No authentication token found')
|
||||
// }
|
||||
|
||||
// const API_BASE_URL = config.api.baseUrl || 'http://localhost:5006'
|
||||
// const response = await fetch(`${API_BASE_URL}/api/v1/auth/nostr/me`, {
|
||||
// headers: {
|
||||
// 'Authorization': `Bearer ${authToken}`,
|
||||
// 'Content-Type': 'application/json'
|
||||
// }
|
||||
// })
|
||||
|
||||
// console.log('API Response status:', response.status)
|
||||
// console.log('API Response headers:', response.headers)
|
||||
|
||||
// const responseText = await response.text()
|
||||
// console.log('API Response text:', responseText)
|
||||
|
||||
// if (response.ok) {
|
||||
// try {
|
||||
// const user = JSON.parse(responseText)
|
||||
// currentUser.value = {
|
||||
// pubkey: user.pubkey,
|
||||
// prvkey: user.prvkey
|
||||
// }
|
||||
// } catch (parseError) {
|
||||
// console.error('JSON Parse Error:', parseError)
|
||||
// console.error('Response was:', responseText)
|
||||
// throw new Error('Invalid JSON response from API')
|
||||
// }
|
||||
// } else {
|
||||
// console.error('API Error:', response.status, responseText)
|
||||
// throw new Error(`Failed to load current user: ${response.status}`)
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('Failed to load current user:', error)
|
||||
// throw error
|
||||
// }
|
||||
// }
|
||||
|
||||
// Subscribe to messages from a specific peer
|
||||
const subscribeToPeer = async (peerPubkey: string) => {
|
||||
if (!currentUser.value) {
|
||||
|
|
@ -364,17 +282,12 @@ export function useNostrChat() {
|
|||
}
|
||||
|
||||
// Check if we have a pool and are connected
|
||||
if (!pool.value) {
|
||||
console.warn('No pool available - initializing...')
|
||||
initializePool()
|
||||
}
|
||||
|
||||
if (!isConnected.value) {
|
||||
if (!relayHub.isConnected.value) {
|
||||
console.warn('Not connected to relays - attempting to connect...')
|
||||
await connect()
|
||||
}
|
||||
|
||||
if (!pool.value) {
|
||||
if (!relayHub.isConnected.value) {
|
||||
throw new Error('Failed to initialize Nostr pool')
|
||||
}
|
||||
|
||||
|
|
@ -398,9 +311,9 @@ export function useNostrChat() {
|
|||
}
|
||||
])
|
||||
|
||||
const sub = pool.value.subscribeMany(
|
||||
relayConfigs.map(r => r.url),
|
||||
[
|
||||
const unsubscribe = relayHub.subscribe({
|
||||
id: `peer-${peerPubkey}-${Date.now()}`,
|
||||
filters: [
|
||||
{
|
||||
kinds: [4],
|
||||
authors: [peerPubkey],
|
||||
|
|
@ -412,18 +325,17 @@ export function useNostrChat() {
|
|||
'#p': [peerPubkey]
|
||||
}
|
||||
],
|
||||
{
|
||||
onevent(event) {
|
||||
console.log('Received live event:', event.id, 'author:', event.pubkey)
|
||||
handleIncomingMessage(event, peerPubkey)
|
||||
},
|
||||
oneose() {
|
||||
console.log('Subscription closed for peer:', peerPubkey)
|
||||
}
|
||||
relays: relayConfigs.map(r => r.url),
|
||||
onEvent: (event: any) => {
|
||||
console.log('Received live event:', event.id, 'author:', event.pubkey)
|
||||
handleIncomingMessage(event, peerPubkey)
|
||||
},
|
||||
onEose: () => {
|
||||
console.log('Subscription closed for peer:', peerPubkey)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
return sub
|
||||
return unsubscribe
|
||||
}
|
||||
|
||||
// Subscribe to a peer for notifications only (without loading full message history)
|
||||
|
|
@ -437,17 +349,12 @@ export function useNostrChat() {
|
|||
}
|
||||
|
||||
// Check if we have a pool and are connected
|
||||
if (!pool.value) {
|
||||
console.warn('No pool available - initializing...')
|
||||
initializePool()
|
||||
}
|
||||
|
||||
if (!isConnected.value) {
|
||||
if (!relayHub.isConnected.value) {
|
||||
console.warn('Not connected to relays - attempting to connect...')
|
||||
await connect()
|
||||
}
|
||||
|
||||
if (!pool.value) {
|
||||
if (!relayHub.isConnected.value) {
|
||||
throw new Error('Failed to initialize Nostr pool')
|
||||
}
|
||||
|
||||
|
|
@ -474,29 +381,28 @@ export function useNostrChat() {
|
|||
|
||||
console.log('Notification subscription filters:', JSON.stringify(filters, null, 2))
|
||||
|
||||
const sub = pool.value.subscribeMany(
|
||||
relayConfigs.map(r => r.url),
|
||||
const unsubscribe = relayHub.subscribe({
|
||||
id: `notifications-${peerPubkey}-${Date.now()}`,
|
||||
filters,
|
||||
{
|
||||
onevent(event) {
|
||||
console.log('Received notification event:', {
|
||||
id: event.id,
|
||||
author: event.pubkey,
|
||||
forPeer: peerPubkey,
|
||||
tags: event.tags,
|
||||
contentLength: event.content?.length || 0
|
||||
})
|
||||
handleIncomingMessage(event, peerPubkey)
|
||||
},
|
||||
oneose() {
|
||||
console.log('Notification subscription closed for peer:', peerPubkey)
|
||||
}
|
||||
relays: relayConfigs.map(r => r.url),
|
||||
onEvent: (event: any) => {
|
||||
console.log('Received notification event:', {
|
||||
id: event.id,
|
||||
author: event.pubkey,
|
||||
forPeer: peerPubkey,
|
||||
tags: event.tags,
|
||||
contentLength: event.content?.length || 0
|
||||
})
|
||||
handleIncomingMessage(event, peerPubkey)
|
||||
},
|
||||
onEose: () => {
|
||||
console.log('Notification subscription closed for peer:', peerPubkey)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
console.log('Successfully created notification subscription for peer:', peerPubkey)
|
||||
console.log('=== SUBSCRIBE TO PEER FOR NOTIFICATIONS END ===')
|
||||
return sub
|
||||
return unsubscribe
|
||||
}
|
||||
|
||||
// Load historical messages for a peer
|
||||
|
|
@ -522,28 +428,27 @@ export function useNostrChat() {
|
|||
|
||||
console.log('Historical query filters:', filters)
|
||||
|
||||
const historicalSub = pool.value!.subscribeMany(
|
||||
relayConfigs.map(r => r.url),
|
||||
const unsubscribe = relayHub.subscribe({
|
||||
id: `historical-${peerPubkey}-${Date.now()}`,
|
||||
filters,
|
||||
{
|
||||
onevent(event) {
|
||||
console.log('Received historical event:', {
|
||||
id: event.id,
|
||||
author: event.pubkey,
|
||||
isSentByMe: event.pubkey === myPubkey,
|
||||
contentLength: event.content.length
|
||||
})
|
||||
handleIncomingMessage(event, peerPubkey)
|
||||
},
|
||||
oneose() {
|
||||
console.log('Historical query completed for peer:', peerPubkey)
|
||||
}
|
||||
relays: relayConfigs.map(r => r.url),
|
||||
onEvent: (event: any) => {
|
||||
console.log('Received historical event:', {
|
||||
id: event.id,
|
||||
author: event.pubkey,
|
||||
isSentByMe: event.pubkey === myPubkey,
|
||||
contentLength: event.content.length
|
||||
})
|
||||
handleIncomingMessage(event, peerPubkey)
|
||||
},
|
||||
onEose: () => {
|
||||
console.log('Historical query completed for peer:', peerPubkey)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
// Wait a bit for historical messages to load
|
||||
await new Promise(resolve => setTimeout(resolve, 3000))
|
||||
historicalSub.close()
|
||||
unsubscribe()
|
||||
console.log('Historical query closed for peer:', peerPubkey)
|
||||
}
|
||||
|
||||
|
|
@ -683,17 +588,12 @@ export function useNostrChat() {
|
|||
}
|
||||
|
||||
// Check if we have a pool and are connected
|
||||
if (!pool.value) {
|
||||
console.warn('No pool available - initializing...')
|
||||
initializePool()
|
||||
}
|
||||
|
||||
if (!isConnected.value) {
|
||||
if (!relayHub.isConnected.value) {
|
||||
console.warn('Not connected to relays - attempting to connect...')
|
||||
await connect()
|
||||
}
|
||||
|
||||
if (!pool.value) {
|
||||
if (!relayHub.isConnected.value) {
|
||||
throw new Error('Failed to initialize Nostr pool')
|
||||
}
|
||||
|
||||
|
|
@ -754,13 +654,8 @@ export function useNostrChat() {
|
|||
// Finalize the event (sign it)
|
||||
const event = finalizeEvent(eventTemplate, hexToBytes(privateKey))
|
||||
|
||||
// Publish to relays
|
||||
const relayConfigs = getRelays()
|
||||
const publishPromises = relayConfigs.map(relay => {
|
||||
return pool.value!.publish([relay.url], event)
|
||||
})
|
||||
|
||||
await Promise.all(publishPromises)
|
||||
// Publish to relays using the relay hub
|
||||
await relayHub.publishEvent(event)
|
||||
|
||||
// Add message to local state
|
||||
const message: ChatMessage = {
|
||||
|
|
@ -857,12 +752,12 @@ export function useNostrChat() {
|
|||
}
|
||||
|
||||
// Wait for connection to be established
|
||||
if (!isConnected.value) {
|
||||
if (!relayHub.isConnected.value) {
|
||||
console.log('Waiting for connection to be established before subscribing to peers')
|
||||
// Wait a bit for connection to establish
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
|
||||
if (!isConnected.value) {
|
||||
if (!relayHub.isConnected.value) {
|
||||
console.warn('Still not connected, skipping peer subscriptions')
|
||||
return
|
||||
}
|
||||
|
|
@ -890,7 +785,7 @@ export function useNostrChat() {
|
|||
peers: readonly(peers),
|
||||
|
||||
// Reactive computed properties
|
||||
totalUnreadCount: readonly(totalUnreadCount),
|
||||
totalUnreadCount: computed(() => getTotalUnreadCount()),
|
||||
|
||||
// Methods
|
||||
connect,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue