From ce81b9d2bfd9c44164566ab8fcf0a545535e00e1 Mon Sep 17 00:00:00 2001 From: padreug Date: Wed, 6 Aug 2025 00:28:03 +0200 Subject: [PATCH] feat: Enhance Nostr chat functionality with historical message loading - Implement a new function to load historical messages for peers before subscribing to new messages, improving user experience by providing context. - Add detailed console logging for both historical and live message events to aid in debugging and understanding message flow. - Ensure consistent handling of conversation keys for both sent and received messages, enhancing message management. --- src/composables/useNostrChat.ts | 110 ++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 5 deletions(-) diff --git a/src/composables/useNostrChat.ts b/src/composables/useNostrChat.ts index 22d221e..1edfa6d 100644 --- a/src/composables/useNostrChat.ts +++ b/src/composables/useNostrChat.ts @@ -176,8 +176,24 @@ export function useNostrChat() { const myPubkey = currentUser.value.pubkey - // Subscribe to direct messages (kind 4) + // First, load historical messages + await loadHistoricalMessages(peerPubkey, myPubkey) + + // Then subscribe to new messages const relayConfigs = getRelays() + console.log('Subscribing to new messages for peer:', peerPubkey, 'with filters:', [ + { + kinds: [4], + authors: [peerPubkey], + '#p': [myPubkey] + }, + { + kinds: [4], + authors: [myPubkey], + '#p': [peerPubkey] + } + ]) + const sub = pool.value.subscribeMany( relayConfigs.map(r => r.url), [ @@ -194,6 +210,7 @@ export function useNostrChat() { ], { onevent(event) { + console.log('Received live event:', event.id, 'author:', event.pubkey) handleIncomingMessage(event, peerPubkey) } } @@ -202,6 +219,54 @@ export function useNostrChat() { return sub } + // Load historical messages for a peer + const loadHistoricalMessages = async (peerPubkey: string, myPubkey: string) => { + console.log('Loading historical messages for peer:', peerPubkey) + console.log('My pubkey:', myPubkey) + + const relayConfigs = getRelays() + console.log('Using relays:', relayConfigs.map(r => r.url)) + + const filters = [ + { + kinds: [4], + authors: [peerPubkey], + '#p': [myPubkey] + }, + { + kinds: [4], + authors: [myPubkey], + '#p': [peerPubkey] + } + ] + + console.log('Historical query filters:', filters) + + const historicalSub = pool.value!.subscribeMany( + relayConfigs.map(r => r.url), + 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) + } + } + ) + + // Wait a bit for historical messages to load + await new Promise(resolve => setTimeout(resolve, 3000)) + historicalSub.close() + console.log('Historical query closed for peer:', peerPubkey) + } + // Handle incoming message const handleIncomingMessage = async (event: any, peerPubkey: string) => { if (processedMessageIds.value.has(event.id)) { @@ -210,13 +275,40 @@ export function useNostrChat() { processedMessageIds.value.add(event.id) + console.log('Handling incoming message:', { + eventId: event.id, + eventPubkey: event.pubkey, + myPubkey: currentUser.value!.pubkey, + peerPubkey, + isSentByMe: event.pubkey === currentUser.value!.pubkey + }) + try { // Decrypt the message + // For NIP-04 direct messages, always use peerPubkey as the second argument + // This is the public key of the other party in the conversation + const isSentByMe = event.pubkey === currentUser.value!.pubkey + + console.log('Decrypting message:', { + eventId: event.id, + isSentByMe, + eventPubkey: event.pubkey, + myPubkey: currentUser.value!.pubkey, + peerPubkey, + contentLength: event.content.length + }) + const decryptedContent = await nip04.decrypt( currentUser.value!.prvkey, - event.pubkey, + peerPubkey, // Always use peerPubkey for shared secret derivation event.content ) + + console.log('Successfully decrypted message:', { + eventId: event.id, + contentLength: decryptedContent.length, + contentPreview: decryptedContent.substring(0, 50) + '...' + }) const message: ChatMessage = { id: event.id, @@ -227,9 +319,10 @@ export function useNostrChat() { } // Add message to the appropriate conversation - const conversationKey = event.pubkey === currentUser.value!.pubkey - ? peerPubkey - : event.pubkey + // Always use peerPubkey as the conversation key for both sent and received messages + const conversationKey = peerPubkey + + console.log('Storing message with conversation key:', conversationKey) if (!messages.value.has(conversationKey)) { messages.value.set(conversationKey, []) @@ -240,6 +333,13 @@ export function useNostrChat() { // Sort messages by timestamp messages.value.get(conversationKey)!.sort((a, b) => a.created_at - b.created_at) + console.log('Messages for conversation:', messages.value.get(conversationKey)?.map(m => ({ + id: m.id, + sent: m.sent, + content: m.content.substring(0, 30) + '...', + timestamp: m.created_at + }))) + } catch (error) { console.error('Failed to decrypt message:', error) }