Enhance Chat and Market Services with improved error handling and logging
Chat Service: - Added detailed logging for API calls and responses, including warnings for missing authentication tokens and invalid response formats. - Implemented a retry mechanism for message subscription setup on connection errors. - Merged peers instead of clearing existing ones when loading from the API. Market Service: - Updated authentication checks to prioritize global auth state, improving user experience during order placement. - Enhanced error messages for missing Nostr keys to guide users in configuring their profiles. These changes improve the robustness and user-friendliness of the chat and market functionalities.
This commit is contained in:
parent
034f3ce80f
commit
8a019db34a
3 changed files with 92 additions and 29 deletions
|
|
@ -316,10 +316,13 @@ export class ChatService extends BaseService {
|
|||
try {
|
||||
const authToken = getAuthToken()
|
||||
if (!authToken) {
|
||||
console.warn('💬 No authentication token found for loading peers from API')
|
||||
throw new Error('No authentication token found')
|
||||
}
|
||||
|
||||
const API_BASE_URL = config.api.baseUrl || 'http://localhost:5006'
|
||||
console.log('💬 Loading peers from API:', `${API_BASE_URL}/api/v1/auth/nostr/pubkeys`)
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/api/v1/auth/nostr/pubkeys`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authToken}`,
|
||||
|
|
@ -328,15 +331,26 @@ export class ChatService extends BaseService {
|
|||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load peers: ${response.status}`)
|
||||
const errorText = await response.text()
|
||||
console.error('💬 API response error:', response.status, errorText)
|
||||
throw new Error(`Failed to load peers: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
console.log('💬 API returned', data?.length || 0, 'peers')
|
||||
|
||||
// Clear existing peers and load from API
|
||||
this.peers.value.clear()
|
||||
if (!Array.isArray(data)) {
|
||||
console.warn('💬 Invalid API response format - expected array, got:', typeof data)
|
||||
return
|
||||
}
|
||||
|
||||
// Don't clear existing peers - merge instead
|
||||
data.forEach((peer: any) => {
|
||||
if (!peer.pubkey) {
|
||||
console.warn('💬 Skipping peer without pubkey:', peer)
|
||||
return
|
||||
}
|
||||
|
||||
const chatPeer: ChatPeer = {
|
||||
pubkey: peer.pubkey,
|
||||
name: peer.username || `User ${peer.pubkey.slice(0, 8)}`,
|
||||
|
|
@ -349,25 +363,31 @@ export class ChatService extends BaseService {
|
|||
// Save to storage
|
||||
this.savePeersToStorage()
|
||||
|
||||
console.log(`Loaded ${data.length} peers from API`)
|
||||
console.log(`✅ Loaded ${data.length} peers from API, total peers now: ${this.peers.value.size}`)
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to load peers from API:', error)
|
||||
throw error
|
||||
console.error('❌ Failed to load peers from API:', error)
|
||||
// Don't re-throw - peers from storage are still available
|
||||
}
|
||||
}
|
||||
|
||||
private loadPeersFromStorage(): void {
|
||||
// Skip loading peers in constructor as StorageService may not be available yet
|
||||
// This will be called later during initialization when dependencies are ready
|
||||
if (!this.isInitialized.value) {
|
||||
if (!this.isInitialized.value || !this.storageService) {
|
||||
this.debug('Skipping peer loading from storage - not initialized or storage unavailable')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const peersArray = this.storageService.getUserData('chat-peers', []) as ChatPeer[]
|
||||
console.log('💬 Loading', peersArray.length, 'peers from storage')
|
||||
peersArray.forEach(peer => {
|
||||
this.peers.value.set(peer.pubkey, peer)
|
||||
})
|
||||
} catch (error) {
|
||||
console.warn('💬 Failed to load peers from storage:', error)
|
||||
}
|
||||
}
|
||||
|
||||
private savePeersToStorage(): void {
|
||||
|
|
@ -465,22 +485,36 @@ export class ChatService extends BaseService {
|
|||
|
||||
if (!this.relayHub || !this.authService?.user?.value?.pubkey) {
|
||||
console.warn('💬 Cannot setup message subscription: missing services')
|
||||
// Retry after a short delay
|
||||
setTimeout(() => this.setupMessageSubscription(), 2000)
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.relayHub.isConnected) {
|
||||
if (!this.relayHub.isConnected.value) {
|
||||
console.warn('💬 RelayHub not connected, waiting for connection...')
|
||||
// Listen for connection event
|
||||
this.relayHub.on('connected', () => {
|
||||
// Listen for connection event - but also set up retry
|
||||
const connectHandler = () => {
|
||||
console.log('💬 RelayHub connected, setting up message subscription...')
|
||||
this.relayHub.off('connected', connectHandler) // Remove listener to prevent multiple calls
|
||||
this.setupMessageSubscription()
|
||||
})
|
||||
}
|
||||
this.relayHub.on('connected', connectHandler)
|
||||
|
||||
// Also set up a fallback retry mechanism
|
||||
setTimeout(() => {
|
||||
if (!this.subscriptionUnsubscriber && this.relayHub.isConnected.value) {
|
||||
console.log('💬 Retry mechanism triggered - setting up subscription')
|
||||
this.setupMessageSubscription()
|
||||
}
|
||||
}, 5000)
|
||||
return
|
||||
}
|
||||
|
||||
const userPubkey = this.authService.user.value.pubkey
|
||||
|
||||
// Subscribe to encrypted direct messages (kind 4) addressed to this user
|
||||
console.log('💬 Setting up chat message subscription for user:', userPubkey.slice(0, 8))
|
||||
|
||||
this.subscriptionUnsubscriber = this.relayHub.subscribe({
|
||||
id: 'chat-messages',
|
||||
filters: [
|
||||
|
|
@ -495,17 +529,25 @@ export class ChatService extends BaseService {
|
|||
return
|
||||
}
|
||||
|
||||
console.log('💬 Received encrypted message from:', event.pubkey.slice(0, 8))
|
||||
await this.processIncomingMessage(event)
|
||||
},
|
||||
onEose: () => {
|
||||
console.log('Chat message subscription EOSE received')
|
||||
console.log('💬 Chat message subscription EOSE received - subscription active')
|
||||
}
|
||||
})
|
||||
|
||||
console.log('Chat message subscription set up successfully')
|
||||
console.log('✅ Chat message subscription set up successfully')
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to setup message subscription:', error)
|
||||
console.error('❌ Failed to setup message subscription:', error)
|
||||
// Retry after a delay on error
|
||||
setTimeout(() => {
|
||||
if (!this.subscriptionUnsubscriber) {
|
||||
console.log('💬 Retrying message subscription setup after error...')
|
||||
this.setupMessageSubscription()
|
||||
}
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { finalizeEvent, type EventTemplate, nip04 } from 'nostr-tools'
|
||||
import { BaseService } from '@/core/base/BaseService'
|
||||
import type { Stall, Product, Order } from '@/stores/market'
|
||||
import { auth } from '@/composables/useAuth'
|
||||
|
||||
export interface NostrmarketStall {
|
||||
id: string
|
||||
|
|
@ -106,15 +107,32 @@ export class NostrmarketService extends BaseService {
|
|||
}
|
||||
|
||||
private getAuth() {
|
||||
if (!this.authService?.isAuthenticated?.value || !this.authService?.user?.value?.prvkey) {
|
||||
throw new Error('User not authenticated or private key not available')
|
||||
// Check global auth first
|
||||
if (!auth.isAuthenticated.value) {
|
||||
throw new Error('User not authenticated')
|
||||
}
|
||||
|
||||
const pubkey = this.authService.user.value.pubkey
|
||||
const prvkey = this.authService.user.value.prvkey
|
||||
// Try to get keys from global auth first, fallback to injected auth service
|
||||
const globalUser = auth.currentUser.value
|
||||
const serviceUser = this.authService?.user?.value
|
||||
|
||||
const pubkey = globalUser?.pubkey || serviceUser?.pubkey
|
||||
const prvkey = globalUser?.prvkey || serviceUser?.prvkey
|
||||
|
||||
if (!pubkey || !prvkey) {
|
||||
throw new Error('Public key or private key is missing')
|
||||
this.debug('Auth check failed:', {
|
||||
globalUser: {
|
||||
exists: !!globalUser,
|
||||
hasPubkey: !!globalUser?.pubkey,
|
||||
hasPrvkey: !!globalUser?.prvkey
|
||||
},
|
||||
serviceUser: {
|
||||
exists: !!serviceUser,
|
||||
hasPubkey: !!serviceUser?.pubkey,
|
||||
hasPrvkey: !!serviceUser?.prvkey
|
||||
}
|
||||
})
|
||||
throw new Error('Nostr keys not available. Please ensure your Nostr identity is configured in your profile.')
|
||||
}
|
||||
|
||||
// Validate that we have proper hex strings
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ import { ref, computed, onMounted } from 'vue'
|
|||
import { useRoute } from 'vue-router'
|
||||
import { useMarketStore } from '@/stores/market'
|
||||
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
|
||||
import { auth } from '@/composables/useAuth'
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
|
|
@ -411,21 +412,23 @@ const placeOrder = async () => {
|
|||
}
|
||||
// Debug logging to understand auth state
|
||||
console.log('Auth check:', {
|
||||
isAuthenticated: authService.isAuthenticated.value,
|
||||
user: authService.user.value,
|
||||
isAuthenticated: auth.isAuthenticated.value,
|
||||
user: auth.currentUser.value,
|
||||
userPubkey: auth.currentUser.value?.pubkey,
|
||||
authServiceUser: authService.user.value,
|
||||
hasPubkey: !!authService.user.value?.pubkey,
|
||||
nostrPubkey: authService.user.value?.pubkey
|
||||
})
|
||||
|
||||
// Get pubkey from auth service
|
||||
const userPubkey = authService.user.value?.pubkey
|
||||
// Try to get pubkey from main auth first, fallback to auth service
|
||||
const userPubkey = auth.currentUser.value?.pubkey || authService.user.value?.pubkey
|
||||
|
||||
if (!authService.isAuthenticated.value) {
|
||||
if (!auth.isAuthenticated.value) {
|
||||
throw new Error('You must be logged in to place an order')
|
||||
}
|
||||
|
||||
if (!userPubkey) {
|
||||
throw new Error('No Nostr public key found. Please ensure your Nostr identity is configured.')
|
||||
throw new Error('Nostr identity required: Please configure your Nostr public key in your profile settings to place orders.')
|
||||
}
|
||||
|
||||
// Create the order using the market store's order placement functionality
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue