updates
This commit is contained in:
parent
d694f9b645
commit
d27f66e95d
5 changed files with 230 additions and 162 deletions
|
|
@ -79,7 +79,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
|
||||||
*/
|
*/
|
||||||
workbox.precacheAndRoute([{
|
workbox.precacheAndRoute([{
|
||||||
"url": "index.html",
|
"url": "index.html",
|
||||||
"revision": "0.dc5rn1lchj8"
|
"revision": "0.36o4mscev7"
|
||||||
}], {});
|
}], {});
|
||||||
workbox.cleanupOutdatedCaches();
|
workbox.cleanupOutdatedCaches();
|
||||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ import { useNostrStore } from '@/stores/nostr'
|
||||||
import { KeyRound, Copy, Check, Eye, EyeOff, Loader2 } from 'lucide-vue-next'
|
import { KeyRound, Copy, Check, Eye, EyeOff, Loader2 } from 'lucide-vue-next'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
|
import { CardDescription, CardTitle } from '@/components/ui/card'
|
||||||
import { isValidPrivateKey, formatPrivateKey } from '@/lib/nostr'
|
import { isValidPrivateKey, formatPrivateKey } from '@/lib/nostr'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
@ -139,7 +139,7 @@ const generateKey = () => {
|
||||||
privkey.value = newKey
|
privkey.value = newKey
|
||||||
error.value = ''
|
error.value = ''
|
||||||
showRecoveryMessage.value = true
|
showRecoveryMessage.value = true
|
||||||
showKey.value = true // Show the key when generated
|
showKey.value = false
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to generate key:', err)
|
console.error('Failed to generate key:', err)
|
||||||
error.value = t('login.error')
|
error.value = t('login.error')
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ const input = ref('')
|
||||||
const isSending = ref(false)
|
const isSending = ref(false)
|
||||||
const error = ref('')
|
const error = ref('')
|
||||||
const messagesEndRef = ref<HTMLDivElement | null>(null)
|
const messagesEndRef = ref<HTMLDivElement | null>(null)
|
||||||
|
const isSubscribing = ref(false)
|
||||||
const SUPPORT_NPUB = import.meta.env.VITE_SUPPORT_NPUB
|
const SUPPORT_NPUB = import.meta.env.VITE_SUPPORT_NPUB
|
||||||
|
|
||||||
if (!SUPPORT_NPUB) {
|
if (!SUPPORT_NPUB) {
|
||||||
|
|
@ -71,11 +72,22 @@ onMounted(async () => {
|
||||||
|
|
||||||
const supportPubkeyHex = npubToHex(SUPPORT_NPUB)
|
const supportPubkeyHex = npubToHex(SUPPORT_NPUB)
|
||||||
nostrStore.activeChat = supportPubkeyHex
|
nostrStore.activeChat = supportPubkeyHex
|
||||||
await nostrStore.subscribeToMessages()
|
|
||||||
|
// Try to subscribe in the background
|
||||||
|
isSubscribing.value = true
|
||||||
|
nostrStore.subscribeToMessages()
|
||||||
|
.catch(err => {
|
||||||
|
console.debug('Support chat subscription error:', err)
|
||||||
|
// Continue anyway - messages will come through when connection succeeds
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
isSubscribing.value = false
|
||||||
|
})
|
||||||
|
|
||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to initialize support chat:', err)
|
console.debug('Support chat setup error:', err)
|
||||||
error.value = 'Failed to connect to support. Please try again later.'
|
// Continue anyway
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -90,10 +102,13 @@ onUnmounted(() => {
|
||||||
watch(() => nostrStore.activeChat, async (newChat) => {
|
watch(() => nostrStore.activeChat, async (newChat) => {
|
||||||
if (newChat) {
|
if (newChat) {
|
||||||
try {
|
try {
|
||||||
|
isSubscribing.value = true
|
||||||
await nostrStore.subscribeToMessages()
|
await nostrStore.subscribeToMessages()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to subscribe to messages:', err)
|
console.debug('Chat subscription error:', err)
|
||||||
error.value = 'Failed to connect to chat. Please try again later.'
|
// Continue anyway
|
||||||
|
} finally {
|
||||||
|
isSubscribing.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -235,6 +250,12 @@ const getMessageGroupClasses = (sent: boolean) => {
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
|
|
||||||
|
<!-- Add loading indicator if needed -->
|
||||||
|
<div v-if="isSubscribing" class="absolute top-4 right-4 flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
|
<div class="h-2 w-2 rounded-full bg-primary animate-pulse"></div>
|
||||||
|
Connecting...
|
||||||
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
import { useNostrStore } from '@/stores/nostr'
|
import { useNostrStore } from '@/stores/nostr'
|
||||||
import SupportChat from '@/components/SupportChat.vue'
|
import SupportChat from '@/components/SupportChat.vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { Dialog, DialogContent } from '@/components/ui/dialog'
|
||||||
|
import Login from '@/components/Login.vue'
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const nostrStore = useNostrStore()
|
const nostrStore = useNostrStore()
|
||||||
|
const showLoginDialog = ref(!nostrStore.isLoggedIn)
|
||||||
|
|
||||||
// Redirect to home if not logged in
|
const handleLoginSuccess = () => {
|
||||||
if (!nostrStore.isLoggedIn) {
|
showLoginDialog.value = false
|
||||||
router.push('/')
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -20,6 +21,13 @@ if (!nostrStore.isLoggedIn) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Login Dialog -->
|
||||||
|
<Dialog v-model:open="showLoginDialog">
|
||||||
|
<DialogContent class="sm:max-w-md">
|
||||||
|
<Login @success="handleLoginSuccess" />
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,6 @@ const DEFAULT_RELAYS = [
|
||||||
'wss://nostr.atitlan.io'
|
'wss://nostr.atitlan.io'
|
||||||
]
|
]
|
||||||
|
|
||||||
// Get support agent's public key from environment variable
|
|
||||||
const SUPPORT_NPUB = import.meta.env.VITE_SUPPORT_NPUB
|
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
async function withTimeout<T>(promise: Promise<T>, timeoutMs: number = 10000): Promise<T> {
|
async function withTimeout<T>(promise: Promise<T>, timeoutMs: number = 10000): Promise<T> {
|
||||||
return Promise.race([
|
return Promise.race([
|
||||||
|
|
@ -132,54 +129,33 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
profiles.value.clear()
|
profiles.value.clear()
|
||||||
processedMessageIds.value.clear()
|
processedMessageIds.value.clear()
|
||||||
|
|
||||||
// Close existing connections
|
// Connect to relays
|
||||||
relayPool.value.forEach(relay => {
|
relayPool.value = (await Promise.all(
|
||||||
try {
|
account.value.relays.map(async relay => {
|
||||||
relay.close()
|
console.log('Connecting to relay:', relay.url)
|
||||||
} catch (err) {
|
const connection = await connectToRelay(relay.url)
|
||||||
console.error('Error closing relay:', err)
|
if (!connection) {
|
||||||
}
|
console.error('Failed to connect to relay:', relay.url)
|
||||||
})
|
}
|
||||||
relayPool.value = []
|
return connection
|
||||||
|
})
|
||||||
// Connect to relays with timeout
|
)).filter((relay): relay is any => relay !== null)
|
||||||
const connectionPromises = account.value.relays.map(async relay => {
|
|
||||||
try {
|
|
||||||
return await withTimeout(connectToRelay(relay.url), 5000)
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`Timeout connecting to ${relay.url}:`, err)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const connectedRelays = await Promise.all(connectionPromises)
|
|
||||||
relayPool.value = connectedRelays.filter((relay): relay is NonNullable<typeof relay> => relay !== null)
|
|
||||||
|
|
||||||
if (relayPool.value.length === 0) {
|
if (relayPool.value.length === 0) {
|
||||||
throw new Error('Failed to connect to any relays')
|
throw new Error('Failed to connect to any relays')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set active chat to support agent first
|
// Setup visibility change handler
|
||||||
activeChat.value = SUPPORT_NPUB
|
setupVisibilityHandler()
|
||||||
|
|
||||||
// Subscribe to messages with shorter timeout
|
// Subscribe to messages in the background
|
||||||
try {
|
subscribeToMessages().catch(err => {
|
||||||
await withTimeout(subscribeToMessages(), 10000)
|
console.error('Background subscription failed:', err)
|
||||||
} catch (err) {
|
})
|
||||||
console.error('Failed to subscribe to messages:', err)
|
|
||||||
// Continue even if subscription fails
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load profiles with shorter timeout
|
|
||||||
try {
|
|
||||||
await withTimeout(loadProfiles(), 5000)
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Failed to load profiles:', err)
|
|
||||||
// Continue even if profile loading fails
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to initialize:', err)
|
console.error('Failed to initialize:', err)
|
||||||
throw new Error('Failed to connect to the network. Please try again.')
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -198,43 +174,9 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
relays: DEFAULT_RELAYS.map(url => ({ url, read: true, write: true }))
|
relays: DEFAULT_RELAYS.map(url => ({ url, read: true, write: true }))
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
// Initialize connection in the background
|
||||||
// Initialize connection with a global timeout
|
init().catch(err => {
|
||||||
await withTimeout(init(), 30000) // 30 second total timeout for the entire login process
|
console.error('Background initialization failed:', err)
|
||||||
} catch (err) {
|
|
||||||
// If initialization fails, clear the account
|
|
||||||
account.value = null
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadProfiles() {
|
|
||||||
if (!account.value) return
|
|
||||||
|
|
||||||
const filter = {
|
|
||||||
kinds: [0],
|
|
||||||
authors: Array.from(messages.value.keys())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter.authors.length === 0) return
|
|
||||||
|
|
||||||
relayPool.value.forEach(relay => {
|
|
||||||
const sub = relay.sub([filter])
|
|
||||||
|
|
||||||
sub.on('event', (event: NostrEvent) => {
|
|
||||||
try {
|
|
||||||
const profile = JSON.parse(event.content)
|
|
||||||
profiles.value.set(event.pubkey, {
|
|
||||||
pubkey: event.pubkey,
|
|
||||||
name: profile.name,
|
|
||||||
picture: profile.picture,
|
|
||||||
about: profile.about,
|
|
||||||
nip05: profile.nip05
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Failed to parse profile:', err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,55 +243,42 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
async function subscribeToMessages() {
|
async function subscribeToMessages() {
|
||||||
if (!account.value) return
|
if (!account.value) return
|
||||||
|
|
||||||
// Cleanup existing subscription if any
|
// Cleanup existing subscription
|
||||||
if (currentSubscription.value) {
|
unsubscribeFromMessages()
|
||||||
unsubscribeFromMessages()
|
|
||||||
}
|
|
||||||
|
|
||||||
let hasReceivedMessage = false
|
// Get timestamp from 24 hours ago
|
||||||
const subscriptionTimeout = setTimeout(() => {
|
const since = Math.floor(Date.now() / 1000) - (24 * 60 * 60)
|
||||||
if (!hasReceivedMessage) {
|
|
||||||
console.log('No messages received, considering subscription successful')
|
|
||||||
hasReceivedMessage = true
|
|
||||||
}
|
|
||||||
}, 5000)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const subscribeToRelay = (relay: any) => {
|
const subscribeToRelay = (relay: any) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let subs: any[] = []
|
const subs: any[] = []
|
||||||
let resolved = false
|
let messageReceived = false
|
||||||
|
let isResolved = false
|
||||||
// Set a timeout for the entire subscription
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
if (!resolved) {
|
|
||||||
console.log('Subscription timeout, but continuing...')
|
|
||||||
resolved = true
|
|
||||||
resolve(true)
|
|
||||||
}
|
|
||||||
}, 8000)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Filter for received messages with history
|
console.log('Setting up subscriptions for relay...')
|
||||||
const receivedFilter = {
|
|
||||||
kinds: [4],
|
|
||||||
'#p': [account.value!.pubkey],
|
|
||||||
since: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter for sent messages with history
|
|
||||||
const sentFilter = {
|
|
||||||
kinds: [4],
|
|
||||||
authors: [account.value!.pubkey],
|
|
||||||
since: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe to received messages
|
// Subscribe to received messages
|
||||||
const receivedSub = relay.sub([receivedFilter])
|
const receivedSub = relay.sub([{
|
||||||
|
kinds: [4],
|
||||||
|
'#p': [account.value!.pubkey],
|
||||||
|
since,
|
||||||
|
}])
|
||||||
subs.push(receivedSub)
|
subs.push(receivedSub)
|
||||||
|
|
||||||
|
// Subscribe to sent messages
|
||||||
|
const sentSub = relay.sub([{
|
||||||
|
kinds: [4],
|
||||||
|
authors: [account.value!.pubkey],
|
||||||
|
since,
|
||||||
|
}])
|
||||||
|
subs.push(sentSub)
|
||||||
|
|
||||||
|
// Handle received messages
|
||||||
receivedSub.on('event', async (event: NostrEvent) => {
|
receivedSub.on('event', async (event: NostrEvent) => {
|
||||||
hasReceivedMessage = true
|
messageReceived = true
|
||||||
|
if (isResolved) return // Don't process events after resolution
|
||||||
try {
|
try {
|
||||||
if (processedMessageIds.value.has(event.id)) return
|
if (processedMessageIds.value.has(event.id)) return
|
||||||
|
|
||||||
|
|
@ -369,21 +298,15 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
|
|
||||||
await addMessage(event.pubkey, dm)
|
await addMessage(event.pubkey, dm)
|
||||||
processedMessageIds.value.add(event.id)
|
processedMessageIds.value.add(event.id)
|
||||||
|
|
||||||
if (!profiles.value.has(event.pubkey)) {
|
|
||||||
await loadProfiles()
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to decrypt received message:', err)
|
console.error('Failed to decrypt received message:', err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Subscribe to sent messages
|
// Handle sent messages
|
||||||
const sentSub = relay.sub([sentFilter])
|
|
||||||
subs.push(sentSub)
|
|
||||||
|
|
||||||
sentSub.on('event', async (event: NostrEvent) => {
|
sentSub.on('event', async (event: NostrEvent) => {
|
||||||
hasReceivedMessage = true
|
messageReceived = true
|
||||||
|
if (isResolved) return // Don't process events after resolution
|
||||||
try {
|
try {
|
||||||
if (processedMessageIds.value.has(event.id)) return
|
if (processedMessageIds.value.has(event.id)) return
|
||||||
|
|
||||||
|
|
@ -414,50 +337,56 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
// Store subscriptions for cleanup
|
// Store subscriptions for cleanup
|
||||||
currentSubscription.value = {
|
currentSubscription.value = {
|
||||||
unsub: () => {
|
unsub: () => {
|
||||||
clearTimeout(timeout)
|
|
||||||
subs.forEach(sub => {
|
subs.forEach(sub => {
|
||||||
try {
|
try {
|
||||||
if (sub && typeof sub.unsub === 'function') {
|
if (sub && typeof sub.unsub === 'function') {
|
||||||
sub.unsub()
|
sub.unsub()
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to unsubscribe:', err)
|
console.debug('Failed to unsubscribe:', err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consider subscription successful immediately
|
// Consider subscription successful after a short delay
|
||||||
if (!resolved) {
|
setTimeout(() => {
|
||||||
resolved = true
|
if (!isResolved) {
|
||||||
resolve(true)
|
isResolved = true
|
||||||
}
|
console.debug(messageReceived ?
|
||||||
|
'Subscription successful with messages' :
|
||||||
|
'Subscription successful, no messages yet'
|
||||||
|
)
|
||||||
|
resolve(true)
|
||||||
|
}
|
||||||
|
}, 3000)
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error in subscription:', err)
|
console.debug('Error in subscription setup:', err)
|
||||||
if (!resolved) {
|
if (!isResolved) {
|
||||||
resolved = true
|
isResolved = true
|
||||||
resolve(true)
|
resolve(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for relays
|
// Wait for all relays to set up subscriptions
|
||||||
await Promise.all(
|
const results = await Promise.all(
|
||||||
relayPool.value.map(relay =>
|
relayPool.value.map(relay => subscribeToRelay(relay))
|
||||||
withTimeout(subscribeToRelay(relay), 10000)
|
|
||||||
.catch(() => true)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
clearTimeout(subscriptionTimeout)
|
// Consider success if at least one relay worked
|
||||||
return true
|
const success = results.some(result => result)
|
||||||
|
if (!success) {
|
||||||
|
console.debug('No relays successfully subscribed')
|
||||||
|
return false // Return false instead of throwing
|
||||||
|
}
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
clearTimeout(subscriptionTimeout)
|
|
||||||
console.error('Failed to subscribe to messages:', err)
|
|
||||||
return true
|
return true
|
||||||
|
} catch (err) {
|
||||||
|
console.debug('Subscription process failed:', err)
|
||||||
|
return false // Return false instead of throwing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -472,6 +401,115 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadProfiles() {
|
||||||
|
if (!account.value) return
|
||||||
|
|
||||||
|
const pubkeysToLoad = new Set<string>()
|
||||||
|
|
||||||
|
// Collect all unique pubkeys from messages
|
||||||
|
for (const [pubkey] of messages.value.entries()) {
|
||||||
|
if (!profiles.value.has(pubkey)) {
|
||||||
|
pubkeysToLoad.add(pubkey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pubkeysToLoad.size === 0) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const filter = {
|
||||||
|
kinds: [0],
|
||||||
|
authors: Array.from(pubkeysToLoad)
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadFromRelay = (relay: any) => {
|
||||||
|
return new Promise<void>((resolve) => {
|
||||||
|
const sub = relay.sub([filter])
|
||||||
|
|
||||||
|
sub.on('event', (event: NostrEvent) => {
|
||||||
|
try {
|
||||||
|
const profile = JSON.parse(event.content)
|
||||||
|
profiles.value.set(event.pubkey, {
|
||||||
|
pubkey: event.pubkey,
|
||||||
|
name: profile.name,
|
||||||
|
picture: profile.picture,
|
||||||
|
about: profile.about,
|
||||||
|
nip05: profile.nip05
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to parse profile:', err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Resolve after receiving EOSE (End of Stored Events)
|
||||||
|
sub.on('eose', () => {
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Set a timeout in case EOSE is not received
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve()
|
||||||
|
}, 5000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load profiles from all relays concurrently
|
||||||
|
await Promise.all(relayPool.value.map(relay => loadFromRelay(relay)))
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to load profiles:', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a reconnection function
|
||||||
|
async function reconnectToRelays() {
|
||||||
|
if (!account.value) return
|
||||||
|
|
||||||
|
console.log('Attempting to reconnect to relays...')
|
||||||
|
|
||||||
|
// Close existing connections
|
||||||
|
relayPool.value.forEach(relay => {
|
||||||
|
try {
|
||||||
|
relay.close()
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error closing relay:', err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
relayPool.value = []
|
||||||
|
|
||||||
|
// Reconnect
|
||||||
|
relayPool.value = (await Promise.all(
|
||||||
|
account.value.relays.map(async relay => {
|
||||||
|
console.log('Reconnecting to relay:', relay.url)
|
||||||
|
const connection = await connectToRelay(relay.url)
|
||||||
|
if (!connection) {
|
||||||
|
console.error('Failed to reconnect to relay:', relay.url)
|
||||||
|
}
|
||||||
|
return connection
|
||||||
|
})
|
||||||
|
)).filter((relay): relay is any => relay !== null)
|
||||||
|
|
||||||
|
if (relayPool.value.length === 0) {
|
||||||
|
throw new Error('Failed to connect to any relays')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resubscribe to messages
|
||||||
|
await subscribeToMessages()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add visibility change handler
|
||||||
|
function setupVisibilityHandler() {
|
||||||
|
document.addEventListener('visibilitychange', async () => {
|
||||||
|
if (document.visibilityState === 'visible' && account.value) {
|
||||||
|
console.log('Page became visible, reconnecting...')
|
||||||
|
try {
|
||||||
|
await reconnectToRelays()
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to reconnect:', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
account,
|
account,
|
||||||
profiles,
|
profiles,
|
||||||
|
|
@ -484,6 +522,7 @@ export const useNostrStore = defineStore('nostr', () => {
|
||||||
logout,
|
logout,
|
||||||
sendMessage,
|
sendMessage,
|
||||||
subscribeToMessages,
|
subscribeToMessages,
|
||||||
unsubscribeFromMessages
|
unsubscribeFromMessages,
|
||||||
|
loadProfiles
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Loading…
Add table
Add a link
Reference in a new issue