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 {
|
try {
|
||||||
const authToken = getAuthToken()
|
const authToken = getAuthToken()
|
||||||
if (!authToken) {
|
if (!authToken) {
|
||||||
|
console.warn('💬 No authentication token found for loading peers from API')
|
||||||
throw new Error('No authentication token found')
|
throw new Error('No authentication token found')
|
||||||
}
|
}
|
||||||
|
|
||||||
const API_BASE_URL = config.api.baseUrl || 'http://localhost:5006'
|
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`, {
|
const response = await fetch(`${API_BASE_URL}/api/v1/auth/nostr/pubkeys`, {
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${authToken}`,
|
'Authorization': `Bearer ${authToken}`,
|
||||||
|
|
@ -328,15 +331,26 @@ export class ChatService extends BaseService {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!response.ok) {
|
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()
|
const data = await response.json()
|
||||||
|
console.log('💬 API returned', data?.length || 0, 'peers')
|
||||||
|
|
||||||
// Clear existing peers and load from API
|
if (!Array.isArray(data)) {
|
||||||
this.peers.value.clear()
|
console.warn('💬 Invalid API response format - expected array, got:', typeof data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't clear existing peers - merge instead
|
||||||
data.forEach((peer: any) => {
|
data.forEach((peer: any) => {
|
||||||
|
if (!peer.pubkey) {
|
||||||
|
console.warn('💬 Skipping peer without pubkey:', peer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const chatPeer: ChatPeer = {
|
const chatPeer: ChatPeer = {
|
||||||
pubkey: peer.pubkey,
|
pubkey: peer.pubkey,
|
||||||
name: peer.username || `User ${peer.pubkey.slice(0, 8)}`,
|
name: peer.username || `User ${peer.pubkey.slice(0, 8)}`,
|
||||||
|
|
@ -349,25 +363,31 @@ export class ChatService extends BaseService {
|
||||||
// Save to storage
|
// Save to storage
|
||||||
this.savePeersToStorage()
|
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) {
|
} catch (error) {
|
||||||
console.error('Failed to load peers from API:', error)
|
console.error('❌ Failed to load peers from API:', error)
|
||||||
throw error
|
// Don't re-throw - peers from storage are still available
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadPeersFromStorage(): void {
|
private loadPeersFromStorage(): void {
|
||||||
// Skip loading peers in constructor as StorageService may not be available yet
|
// Skip loading peers in constructor as StorageService may not be available yet
|
||||||
// This will be called later during initialization when dependencies are ready
|
// 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const peersArray = this.storageService.getUserData('chat-peers', []) as ChatPeer[]
|
try {
|
||||||
peersArray.forEach(peer => {
|
const peersArray = this.storageService.getUserData('chat-peers', []) as ChatPeer[]
|
||||||
this.peers.value.set(peer.pubkey, peer)
|
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 {
|
private savePeersToStorage(): void {
|
||||||
|
|
@ -465,22 +485,36 @@ export class ChatService extends BaseService {
|
||||||
|
|
||||||
if (!this.relayHub || !this.authService?.user?.value?.pubkey) {
|
if (!this.relayHub || !this.authService?.user?.value?.pubkey) {
|
||||||
console.warn('💬 Cannot setup message subscription: missing services')
|
console.warn('💬 Cannot setup message subscription: missing services')
|
||||||
|
// Retry after a short delay
|
||||||
|
setTimeout(() => this.setupMessageSubscription(), 2000)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.relayHub.isConnected) {
|
if (!this.relayHub.isConnected.value) {
|
||||||
console.warn('💬 RelayHub not connected, waiting for connection...')
|
console.warn('💬 RelayHub not connected, waiting for connection...')
|
||||||
// Listen for connection event
|
// Listen for connection event - but also set up retry
|
||||||
this.relayHub.on('connected', () => {
|
const connectHandler = () => {
|
||||||
console.log('💬 RelayHub connected, setting up message subscription...')
|
console.log('💬 RelayHub connected, setting up message subscription...')
|
||||||
|
this.relayHub.off('connected', connectHandler) // Remove listener to prevent multiple calls
|
||||||
this.setupMessageSubscription()
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const userPubkey = this.authService.user.value.pubkey
|
const userPubkey = this.authService.user.value.pubkey
|
||||||
|
|
||||||
// Subscribe to encrypted direct messages (kind 4) addressed to this user
|
// 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({
|
this.subscriptionUnsubscriber = this.relayHub.subscribe({
|
||||||
id: 'chat-messages',
|
id: 'chat-messages',
|
||||||
filters: [
|
filters: [
|
||||||
|
|
@ -495,17 +529,25 @@ export class ChatService extends BaseService {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('💬 Received encrypted message from:', event.pubkey.slice(0, 8))
|
||||||
await this.processIncomingMessage(event)
|
await this.processIncomingMessage(event)
|
||||||
},
|
},
|
||||||
onEose: () => {
|
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) {
|
} 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 { finalizeEvent, type EventTemplate, nip04 } from 'nostr-tools'
|
||||||
import { BaseService } from '@/core/base/BaseService'
|
import { BaseService } from '@/core/base/BaseService'
|
||||||
import type { Stall, Product, Order } from '@/stores/market'
|
import type { Stall, Product, Order } from '@/stores/market'
|
||||||
|
import { auth } from '@/composables/useAuth'
|
||||||
|
|
||||||
export interface NostrmarketStall {
|
export interface NostrmarketStall {
|
||||||
id: string
|
id: string
|
||||||
|
|
@ -106,15 +107,32 @@ export class NostrmarketService extends BaseService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private getAuth() {
|
private getAuth() {
|
||||||
if (!this.authService?.isAuthenticated?.value || !this.authService?.user?.value?.prvkey) {
|
// Check global auth first
|
||||||
throw new Error('User not authenticated or private key not available')
|
if (!auth.isAuthenticated.value) {
|
||||||
|
throw new Error('User not authenticated')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 = this.authService.user.value.pubkey
|
const pubkey = globalUser?.pubkey || serviceUser?.pubkey
|
||||||
const prvkey = this.authService.user.value.prvkey
|
const prvkey = globalUser?.prvkey || serviceUser?.prvkey
|
||||||
|
|
||||||
if (!pubkey || !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
|
// Validate that we have proper hex strings
|
||||||
|
|
|
||||||
|
|
@ -272,6 +272,7 @@ import { ref, computed, onMounted } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { useMarketStore } from '@/stores/market'
|
import { useMarketStore } from '@/stores/market'
|
||||||
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
|
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
|
||||||
|
import { auth } from '@/composables/useAuth'
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
|
|
@ -411,21 +412,23 @@ const placeOrder = async () => {
|
||||||
}
|
}
|
||||||
// Debug logging to understand auth state
|
// Debug logging to understand auth state
|
||||||
console.log('Auth check:', {
|
console.log('Auth check:', {
|
||||||
isAuthenticated: authService.isAuthenticated.value,
|
isAuthenticated: auth.isAuthenticated.value,
|
||||||
user: authService.user.value,
|
user: auth.currentUser.value,
|
||||||
|
userPubkey: auth.currentUser.value?.pubkey,
|
||||||
|
authServiceUser: authService.user.value,
|
||||||
hasPubkey: !!authService.user.value?.pubkey,
|
hasPubkey: !!authService.user.value?.pubkey,
|
||||||
nostrPubkey: authService.user.value?.pubkey
|
nostrPubkey: authService.user.value?.pubkey
|
||||||
})
|
})
|
||||||
|
|
||||||
// Get pubkey from auth service
|
// Try to get pubkey from main auth first, fallback to auth service
|
||||||
const userPubkey = authService.user.value?.pubkey
|
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')
|
throw new Error('You must be logged in to place an order')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userPubkey) {
|
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
|
// Create the order using the market store's order placement functionality
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue