Remove LEGACY Nostr client services and related components to streamline the codebase
- Delete Nostr client hub and associated files, including the Nostr store, to eliminate unused functionality. - Update service tokens and dependency injections to reflect the removal of Nostr client services. - Adjust notification settings in NotificationSettings.vue to prepare for future implementation of notifications.
This commit is contained in:
parent
92c33aa0a3
commit
7e4b64b831
8 changed files with 7 additions and 661 deletions
|
|
@ -78,7 +78,6 @@ const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB)
|
|||
|
||||
**Available Services:**
|
||||
- `SERVICE_TOKENS.RELAY_HUB` - Centralized Nostr relay management
|
||||
- `SERVICE_TOKENS.NOSTR_CLIENT_HUB` - Nostr client services
|
||||
- `SERVICE_TOKENS.AUTH_SERVICE` - Authentication services
|
||||
- `SERVICE_TOKENS.VISIBILITY_SERVICE` - App visibility and connection management
|
||||
|
||||
|
|
|
|||
|
|
@ -151,15 +151,13 @@ import { Button } from '@/components/ui/button'
|
|||
import { Label } from '@/components/ui/label'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Bell, BellOff, TestTube, AlertCircle } from 'lucide-vue-next'
|
||||
import { useNostrStore } from '@/stores/nostr'
|
||||
import { notificationManager } from '@/lib/notifications/manager'
|
||||
import { pushService } from '@/lib/notifications/push'
|
||||
import { configUtils } from '@/lib/config'
|
||||
import { toast } from 'vue-sonner'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
const nostrStore = useNostrStore()
|
||||
const { notificationsEnabled } = storeToRefs(nostrStore)
|
||||
// Placeholder for notifications - will be implemented later
|
||||
const notificationsEnabled = ref(false)
|
||||
|
||||
const isLoading = ref(false)
|
||||
const isTestLoading = ref(false)
|
||||
|
|
@ -174,14 +172,14 @@ onMounted(async () => {
|
|||
|
||||
async function checkStatus() {
|
||||
isBlocked.value = pushService.getPermission() === 'denied'
|
||||
await nostrStore.checkPushNotificationStatus()
|
||||
// TODO: Implement push notification status checking when notifications are re-added
|
||||
}
|
||||
|
||||
async function enableNotifications() {
|
||||
try {
|
||||
isLoading.value = true
|
||||
await nostrStore.enablePushNotifications()
|
||||
toast.success('Push notifications enabled!')
|
||||
// TODO: Implement push notification enabling when notifications are re-added
|
||||
toast.success('Push notifications will be implemented later')
|
||||
await checkStatus()
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Failed to enable notifications'
|
||||
|
|
@ -193,7 +191,7 @@ async function enableNotifications() {
|
|||
|
||||
async function disableNotifications() {
|
||||
try {
|
||||
await nostrStore.disablePushNotifications()
|
||||
// TODO: Implement push notification disabling when notifications are re-added
|
||||
toast.success('Push notifications disabled')
|
||||
await checkStatus()
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ export abstract class BaseService {
|
|||
// Core dependencies with proper typing
|
||||
protected relayHub: any = null
|
||||
protected authService: any = null
|
||||
protected nostrClientHub: any = null
|
||||
protected visibilityService: any = null
|
||||
|
||||
// Service state
|
||||
|
|
@ -134,7 +133,6 @@ export abstract class BaseService {
|
|||
// Try to inject core dependencies
|
||||
this.relayHub = tryInjectService(SERVICE_TOKENS.RELAY_HUB)
|
||||
this.authService = tryInjectService(SERVICE_TOKENS.AUTH_SERVICE)
|
||||
this.nostrClientHub = tryInjectService(SERVICE_TOKENS.NOSTR_CLIENT_HUB)
|
||||
this.visibilityService = tryInjectService(SERVICE_TOKENS.VISIBILITY_SERVICE)
|
||||
|
||||
// Check if all required dependencies are available
|
||||
|
|
@ -180,9 +178,6 @@ export abstract class BaseService {
|
|||
if (deps.includes('AuthService') && !this.authService) {
|
||||
missing.push('AuthService')
|
||||
}
|
||||
if (deps.includes('NostrClientHub') && !this.nostrClientHub) {
|
||||
missing.push('NostrClientHub')
|
||||
}
|
||||
if (deps.includes('VisibilityService') && !this.visibilityService) {
|
||||
missing.push('VisibilityService')
|
||||
}
|
||||
|
|
@ -269,7 +264,6 @@ export abstract class BaseService {
|
|||
this.isInitialized.value = false
|
||||
this.relayHub = null
|
||||
this.authService = null
|
||||
this.nostrClientHub = null
|
||||
|
||||
console.log(`♻️ ${this.metadata.name} disposed`)
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,6 @@ export const SERVICE_TOKENS = {
|
|||
|
||||
// Nostr services
|
||||
RELAY_HUB: Symbol('relayHub'),
|
||||
NOSTR_CLIENT_HUB: Symbol('nostrClientHub'),
|
||||
|
||||
// Auth services
|
||||
AUTH_SERVICE: Symbol('authService'),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import type { App } from 'vue'
|
|||
import type { ModulePlugin } from '@/core/types'
|
||||
import { container, SERVICE_TOKENS } from '@/core/di-container'
|
||||
import { relayHub } from './nostr/relay-hub'
|
||||
import { nostrclientHub } from './nostr/nostrclient-hub'
|
||||
|
||||
// Import auth services
|
||||
import { auth } from './auth/auth-service'
|
||||
|
|
@ -27,7 +26,6 @@ export const baseModule: ModulePlugin = {
|
|||
|
||||
// Register core Nostr services
|
||||
container.provide(SERVICE_TOKENS.RELAY_HUB, relayHub)
|
||||
container.provide(SERVICE_TOKENS.NOSTR_CLIENT_HUB, nostrclientHub)
|
||||
|
||||
// Register auth service
|
||||
container.provide(SERVICE_TOKENS.AUTH_SERVICE, auth)
|
||||
|
|
@ -56,10 +54,6 @@ export const baseModule: ModulePlugin = {
|
|||
waitForDependencies: false, // VisibilityService has no dependencies
|
||||
maxRetries: 1
|
||||
})
|
||||
await nostrclientHub.initialize({
|
||||
waitForDependencies: true, // NostrClientHub depends on VisibilityService
|
||||
maxRetries: 3
|
||||
})
|
||||
|
||||
console.log('✅ Base module installed successfully')
|
||||
},
|
||||
|
|
@ -69,7 +63,6 @@ export const baseModule: ModulePlugin = {
|
|||
|
||||
// Cleanup services
|
||||
await relayHub.dispose()
|
||||
await nostrclientHub.dispose()
|
||||
await auth.dispose()
|
||||
await paymentService.dispose()
|
||||
await visibilityService.dispose()
|
||||
|
|
@ -79,7 +72,6 @@ export const baseModule: ModulePlugin = {
|
|||
|
||||
services: {
|
||||
relayHub,
|
||||
nostrclientHub,
|
||||
auth,
|
||||
paymentService,
|
||||
pwaService
|
||||
|
|
|
|||
|
|
@ -1,16 +1,10 @@
|
|||
// Re-export Nostr infrastructure from base module
|
||||
export { RelayHub } from './relay-hub'
|
||||
export { NostrclientHub } from './nostrclient-hub'
|
||||
export { relayHub } from './relay-hub'
|
||||
export { nostrclientHub } from './nostrclient-hub'
|
||||
|
||||
// Re-export types
|
||||
export type {
|
||||
RelayConfig,
|
||||
SubscriptionConfig,
|
||||
RelayStatus
|
||||
} from './relay-hub'
|
||||
|
||||
export type {
|
||||
NostrclientConfig
|
||||
} from './nostrclient-hub'
|
||||
} from './relay-hub'
|
||||
|
|
@ -1,442 +0,0 @@
|
|||
import type { Filter, Event } from 'nostr-tools'
|
||||
import { BaseService } from '@/core/base/BaseService'
|
||||
|
||||
|
||||
export interface NostrclientConfig {
|
||||
url: string
|
||||
privateKey?: string // For private WebSocket endpoint
|
||||
}
|
||||
|
||||
export interface SubscriptionConfig {
|
||||
id: string
|
||||
filters: Filter[]
|
||||
onEvent?: (event: Event) => void
|
||||
onEose?: () => void
|
||||
onClose?: () => void
|
||||
}
|
||||
|
||||
export interface RelayStatus {
|
||||
url: string
|
||||
connected: boolean
|
||||
lastSeen: number
|
||||
error?: string
|
||||
}
|
||||
|
||||
export class NostrclientHub extends BaseService {
|
||||
// Service metadata
|
||||
protected readonly metadata = {
|
||||
name: 'NostrclientHub',
|
||||
version: '1.0.0',
|
||||
dependencies: ['VisibilityService']
|
||||
}
|
||||
|
||||
// EventEmitter functionality
|
||||
private events: { [key: string]: Function[] } = {}
|
||||
|
||||
// Service state
|
||||
private ws: WebSocket | null = null
|
||||
private config: NostrclientConfig
|
||||
private subscriptions: Map<string, SubscriptionConfig> = new Map()
|
||||
private reconnectInterval?: number
|
||||
private reconnectAttempts = 0
|
||||
private readonly maxReconnectAttempts = 5
|
||||
private readonly reconnectDelay = 5000
|
||||
private visibilityUnsubscribe?: () => void
|
||||
|
||||
// Connection state
|
||||
private _isConnected = false
|
||||
private _isConnecting = false
|
||||
|
||||
constructor(config: NostrclientConfig) {
|
||||
super()
|
||||
this.config = config
|
||||
}
|
||||
|
||||
// EventEmitter methods
|
||||
on(event: string, listener: Function) {
|
||||
if (!this.events[event]) {
|
||||
this.events[event] = []
|
||||
}
|
||||
this.events[event].push(listener)
|
||||
}
|
||||
|
||||
emit(event: string, ...args: any[]) {
|
||||
if (this.events[event]) {
|
||||
this.events[event].forEach(listener => listener(...args))
|
||||
}
|
||||
}
|
||||
|
||||
removeAllListeners(event?: string) {
|
||||
if (event) {
|
||||
delete this.events[event]
|
||||
} else {
|
||||
this.events = {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Service-specific initialization (called by BaseService)
|
||||
*/
|
||||
protected async onInitialize(): Promise<void> {
|
||||
// Connect to WebSocket
|
||||
console.log('🔧 NostrclientHub: Initializing connection to', this.config.url)
|
||||
await this.connect()
|
||||
|
||||
// Register with visibility service
|
||||
this.registerWithVisibilityService()
|
||||
|
||||
this.debug('NostrclientHub initialized')
|
||||
}
|
||||
|
||||
get isConnected(): boolean {
|
||||
return this._isConnected
|
||||
}
|
||||
|
||||
get isConnecting(): boolean {
|
||||
return this._isConnecting
|
||||
}
|
||||
|
||||
get totalSubscriptionCount(): number {
|
||||
return this.subscriptions.size
|
||||
}
|
||||
|
||||
get subscriptionDetails(): Array<{ id: string; filters: Filter[] }> {
|
||||
return Array.from(this.subscriptions.values()).map(sub => ({
|
||||
id: sub.id,
|
||||
filters: sub.filters
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Connect to the nostrclient WebSocket
|
||||
*/
|
||||
async connect(): Promise<void> {
|
||||
if (this._isConnecting || this._isConnected) {
|
||||
return
|
||||
}
|
||||
|
||||
this._isConnecting = true
|
||||
this.reconnectAttempts++
|
||||
|
||||
try {
|
||||
console.log('🔧 NostrclientHub: Connecting to nostrclient WebSocket')
|
||||
|
||||
// Determine WebSocket endpoint
|
||||
const wsUrl = this.config.privateKey
|
||||
? `${this.config.url}/${this.config.privateKey}` // Private endpoint
|
||||
: `${this.config.url}/relay` // Public endpoint
|
||||
|
||||
this.ws = new WebSocket(wsUrl)
|
||||
|
||||
this.ws.onopen = () => {
|
||||
console.log('🔧 NostrclientHub: WebSocket connected')
|
||||
this._isConnected = true
|
||||
this._isConnecting = false
|
||||
this.reconnectAttempts = 0
|
||||
this.emit('connected')
|
||||
|
||||
// Resubscribe to existing subscriptions
|
||||
this.resubscribeAll()
|
||||
}
|
||||
|
||||
this.ws.onmessage = (event) => {
|
||||
this.handleMessage(event.data)
|
||||
}
|
||||
|
||||
this.ws.onclose = (event) => {
|
||||
console.log('🔧 NostrclientHub: WebSocket closed:', event.code, event.reason)
|
||||
this._isConnected = false
|
||||
this._isConnecting = false
|
||||
this.emit('disconnected', event)
|
||||
|
||||
// Schedule reconnection
|
||||
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
||||
this.scheduleReconnect()
|
||||
} else {
|
||||
this.emit('maxReconnectionAttemptsReached')
|
||||
}
|
||||
}
|
||||
|
||||
this.ws.onerror = (error) => {
|
||||
console.error('🔧 NostrclientHub: WebSocket error:', error)
|
||||
this.emit('error', error)
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
this._isConnecting = false
|
||||
console.error('🔧 NostrclientHub: Connection failed:', error)
|
||||
this.emit('connectionError', error)
|
||||
|
||||
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
||||
this.scheduleReconnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the WebSocket
|
||||
*/
|
||||
disconnect(): void {
|
||||
if (this.reconnectInterval) {
|
||||
clearTimeout(this.reconnectInterval)
|
||||
this.reconnectInterval = undefined
|
||||
}
|
||||
|
||||
if (this.ws) {
|
||||
this.ws.close()
|
||||
this.ws = null
|
||||
}
|
||||
|
||||
this._isConnected = false
|
||||
this._isConnecting = false
|
||||
this.subscriptions.clear()
|
||||
this.emit('disconnected')
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to events
|
||||
*/
|
||||
subscribe(config: SubscriptionConfig): () => void {
|
||||
if (!this._isConnected) {
|
||||
throw new Error('Not connected to nostrclient')
|
||||
}
|
||||
|
||||
// Store subscription
|
||||
this.subscriptions.set(config.id, config)
|
||||
|
||||
// Send REQ message
|
||||
const reqMessage = JSON.stringify([
|
||||
'REQ',
|
||||
config.id,
|
||||
...config.filters
|
||||
])
|
||||
|
||||
this.ws?.send(reqMessage)
|
||||
console.log('🔧 NostrclientHub: Subscribed to', config.id)
|
||||
|
||||
// Return unsubscribe function
|
||||
return () => {
|
||||
this.unsubscribe(config.id)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from events
|
||||
*/
|
||||
unsubscribe(subscriptionId: string): void {
|
||||
if (!this._isConnected) {
|
||||
return
|
||||
}
|
||||
|
||||
// Send CLOSE message
|
||||
const closeMessage = JSON.stringify(['CLOSE', subscriptionId])
|
||||
this.ws?.send(closeMessage)
|
||||
|
||||
// Remove from subscriptions
|
||||
this.subscriptions.delete(subscriptionId)
|
||||
console.log('🔧 NostrclientHub: Unsubscribed from', subscriptionId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish an event
|
||||
*/
|
||||
async publishEvent(event: Event): Promise<void> {
|
||||
if (!this._isConnected) {
|
||||
throw new Error('Not connected to nostrclient')
|
||||
}
|
||||
|
||||
const eventMessage = JSON.stringify(['EVENT', event])
|
||||
this.ws?.send(eventMessage)
|
||||
|
||||
console.log('🔧 NostrclientHub: Published event', event.id)
|
||||
this.emit('eventPublished', { eventId: event.id })
|
||||
}
|
||||
|
||||
/**
|
||||
* Query events (one-time fetch)
|
||||
*/
|
||||
async queryEvents(filters: Filter[]): Promise<Event[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._isConnected) {
|
||||
reject(new Error('Not connected to nostrclient'))
|
||||
return
|
||||
}
|
||||
|
||||
const queryId = `query-${Date.now()}`
|
||||
const events: Event[] = []
|
||||
let eoseReceived = false
|
||||
|
||||
// Create temporary subscription for query
|
||||
const tempSubscription = this.subscribe({
|
||||
id: queryId,
|
||||
filters,
|
||||
onEvent: (event) => {
|
||||
events.push(event)
|
||||
},
|
||||
onEose: () => {
|
||||
eoseReceived = true
|
||||
this.unsubscribe(queryId)
|
||||
resolve(events)
|
||||
},
|
||||
onClose: () => {
|
||||
if (!eoseReceived) {
|
||||
reject(new Error('Query subscription closed unexpectedly'))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Timeout after 30 seconds
|
||||
setTimeout(() => {
|
||||
if (!eoseReceived) {
|
||||
tempSubscription()
|
||||
reject(new Error('Query timeout'))
|
||||
}
|
||||
}, 30000)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incoming WebSocket messages
|
||||
*/
|
||||
private handleMessage(data: string): void {
|
||||
try {
|
||||
const message = JSON.parse(data)
|
||||
|
||||
if (Array.isArray(message) && message.length >= 2) {
|
||||
const [type, subscriptionId, ...rest] = message
|
||||
|
||||
switch (type) {
|
||||
case 'EVENT':
|
||||
const event = rest[0] as Event
|
||||
const subscription = this.subscriptions.get(subscriptionId)
|
||||
if (subscription?.onEvent) {
|
||||
subscription.onEvent(event)
|
||||
}
|
||||
this.emit('event', { subscriptionId, event })
|
||||
break
|
||||
|
||||
case 'EOSE':
|
||||
const eoseSubscription = this.subscriptions.get(subscriptionId)
|
||||
if (eoseSubscription?.onEose) {
|
||||
eoseSubscription.onEose()
|
||||
}
|
||||
this.emit('eose', { subscriptionId })
|
||||
break
|
||||
|
||||
case 'NOTICE':
|
||||
console.log('🔧 NostrclientHub: Notice from relay:', rest[0])
|
||||
this.emit('notice', { message: rest[0] })
|
||||
break
|
||||
|
||||
default:
|
||||
console.log('🔧 NostrclientHub: Unknown message type:', type)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('🔧 NostrclientHub: Failed to parse message:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resubscribe to all existing subscriptions after reconnection
|
||||
*/
|
||||
private resubscribeAll(): void {
|
||||
for (const [id, config] of this.subscriptions) {
|
||||
const reqMessage = JSON.stringify([
|
||||
'REQ',
|
||||
id,
|
||||
...config.filters
|
||||
])
|
||||
this.ws?.send(reqMessage)
|
||||
}
|
||||
console.log('🔧 NostrclientHub: Resubscribed to', this.subscriptions.size, 'subscriptions')
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule automatic reconnection
|
||||
*/
|
||||
private scheduleReconnect(): void {
|
||||
if (this.reconnectInterval) {
|
||||
clearTimeout(this.reconnectInterval)
|
||||
}
|
||||
|
||||
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1)
|
||||
console.log(`🔧 NostrclientHub: Scheduling reconnection in ${delay}ms`)
|
||||
|
||||
this.reconnectInterval = setTimeout(async () => {
|
||||
await this.connect()
|
||||
}, delay) as unknown as number
|
||||
}
|
||||
|
||||
/**
|
||||
* Register with VisibilityService for connection management
|
||||
*/
|
||||
private registerWithVisibilityService(): void {
|
||||
if (!this.visibilityService) {
|
||||
this.debug('VisibilityService not available')
|
||||
return
|
||||
}
|
||||
|
||||
this.visibilityUnsubscribe = this.visibilityService.registerService(
|
||||
this.metadata.name,
|
||||
async () => this.handleAppResume(),
|
||||
async () => this.handleAppPause()
|
||||
)
|
||||
|
||||
this.debug('Registered with VisibilityService')
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle app resuming from visibility change
|
||||
*/
|
||||
private async handleAppResume(): Promise<void> {
|
||||
this.debug('App resumed - checking nostrclient WebSocket connection')
|
||||
|
||||
// Check if we need to reconnect
|
||||
if (!this.isConnected && !this._isConnecting) {
|
||||
this.debug('WebSocket disconnected, attempting to reconnect...')
|
||||
await this.connect()
|
||||
} else if (this.isConnected) {
|
||||
// Connection is alive, resubscribe to ensure all subscriptions are active
|
||||
this.resubscribeAll()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle app pausing from visibility change
|
||||
*/
|
||||
private async handleAppPause(): Promise<void> {
|
||||
this.debug('App paused - WebSocket connection will be maintained for quick resume')
|
||||
|
||||
// Don't immediately disconnect - WebSocket will be checked on resume
|
||||
// This allows for quick resume without full reconnection overhead
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup when service is disposed (overrides BaseService)
|
||||
*/
|
||||
protected async onDispose(): Promise<void> {
|
||||
// Unregister from visibility service
|
||||
if (this.visibilityUnsubscribe) {
|
||||
this.visibilityUnsubscribe()
|
||||
this.visibilityUnsubscribe = undefined
|
||||
}
|
||||
|
||||
// Disconnect WebSocket
|
||||
this.disconnect()
|
||||
|
||||
// Clear all event listeners
|
||||
this.removeAllListeners()
|
||||
|
||||
this.debug('NostrclientHub disposed')
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const nostrclientHub = new NostrclientHub({
|
||||
url: import.meta.env.VITE_NOSTRCLIENT_URL || 'wss://localhost:5000/nostrclient/api/v1'
|
||||
})
|
||||
|
||||
// Ensure global export
|
||||
;(globalThis as any).nostrclientHub = nostrclientHub
|
||||
|
|
@ -1,188 +0,0 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { relayHub } from '@/lib/nostr/relayHub'
|
||||
import { config } from '@/lib/config'
|
||||
import { pushService, type PushSubscriptionData } from '@/lib/notifications/push'
|
||||
|
||||
// Define an interface for the account object
|
||||
interface NostrAccount {
|
||||
privkey: string
|
||||
pubkey: string
|
||||
}
|
||||
|
||||
export const useNostrStore = defineStore('nostr', () => {
|
||||
// Connection state
|
||||
const isConnected = ref(false)
|
||||
const isConnecting = ref(false)
|
||||
const error = ref<Error | null>(null)
|
||||
|
||||
// Configuration
|
||||
const relayUrls = ref<string[]>(config.nostr.relays)
|
||||
const account = ref<NostrAccount | null>(null)
|
||||
|
||||
// Push notifications
|
||||
const pushSubscription = ref<PushSubscriptionData | null>(null)
|
||||
const notificationsEnabled = ref(false)
|
||||
|
||||
// Connection management
|
||||
async function connect(): Promise<void> {
|
||||
try {
|
||||
error.value = null
|
||||
isConnecting.value = true
|
||||
|
||||
// Initialize and connect using the centralized relay hub
|
||||
await relayHub.initialize(relayUrls.value)
|
||||
await relayHub.connect()
|
||||
|
||||
isConnected.value = relayHub.isConnected
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err : new Error('Failed to connect')
|
||||
isConnected.value = false
|
||||
throw err
|
||||
} finally {
|
||||
isConnecting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function disconnect(): void {
|
||||
// Don't disconnect the relay hub as it's managed centrally
|
||||
// Just update our local state
|
||||
isConnected.value = false
|
||||
isConnecting.value = false
|
||||
error.value = null
|
||||
}
|
||||
|
||||
// Configuration setters
|
||||
function setConnected(value: boolean) {
|
||||
isConnected.value = value
|
||||
}
|
||||
|
||||
function setRelayUrls(urls: string[]) {
|
||||
relayUrls.value = urls
|
||||
// The relay hub will handle reconnection with new relays if needed
|
||||
}
|
||||
|
||||
function setAccount(nostrAccount: NostrAccount | null) {
|
||||
account.value = nostrAccount
|
||||
}
|
||||
|
||||
// Push notification management
|
||||
async function enablePushNotifications(): Promise<PushSubscriptionData> {
|
||||
try {
|
||||
const subscription = await pushService.subscribe()
|
||||
pushSubscription.value = subscription
|
||||
notificationsEnabled.value = true
|
||||
|
||||
// Store subscription in localStorage for persistence
|
||||
localStorage.setItem('push-subscription', JSON.stringify(subscription))
|
||||
localStorage.setItem('notifications-enabled', 'true')
|
||||
|
||||
return subscription
|
||||
} catch (error) {
|
||||
console.error('Failed to enable push notifications:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function disablePushNotifications(): Promise<void> {
|
||||
try {
|
||||
await pushService.unsubscribe()
|
||||
pushSubscription.value = null
|
||||
notificationsEnabled.value = false
|
||||
|
||||
// Remove from localStorage
|
||||
localStorage.removeItem('push-subscription')
|
||||
localStorage.removeItem('notifications-enabled')
|
||||
} catch (error) {
|
||||
console.error('Failed to disable push notifications:', error)
|
||||
}
|
||||
}
|
||||
|
||||
async function checkPushNotificationStatus(): Promise<void> {
|
||||
try {
|
||||
// Check localStorage first
|
||||
const storedEnabled = localStorage.getItem('notifications-enabled') === 'true'
|
||||
const storedSubscription = localStorage.getItem('push-subscription')
|
||||
|
||||
if (storedEnabled && storedSubscription) {
|
||||
pushSubscription.value = JSON.parse(storedSubscription)
|
||||
notificationsEnabled.value = true
|
||||
}
|
||||
|
||||
// Verify with push service
|
||||
const currentSubscription = await pushService.getSubscription()
|
||||
if (currentSubscription) {
|
||||
pushSubscription.value = currentSubscription
|
||||
notificationsEnabled.value = true
|
||||
} else if (storedEnabled) {
|
||||
// Stored state says enabled but no actual subscription - clear stored state
|
||||
await disablePushNotifications()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to check push notification status:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Send test notification
|
||||
async function sendTestNotification(): Promise<void> {
|
||||
await pushService.showLocalNotification({
|
||||
title: '🚨 Test Admin Announcement',
|
||||
body: 'This is a test notification to verify push notifications are working correctly.',
|
||||
icon: '/pwa-192x192.png',
|
||||
tag: 'test-notification',
|
||||
data: {
|
||||
url: '/',
|
||||
type: 'admin-announcement'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Setup relay hub event listeners to keep store state in sync
|
||||
function setupRelayHubListeners(): void {
|
||||
relayHub.on('connected', () => {
|
||||
isConnected.value = true
|
||||
isConnecting.value = false
|
||||
error.value = null
|
||||
})
|
||||
|
||||
relayHub.on('disconnected', () => {
|
||||
isConnected.value = false
|
||||
isConnecting.value = false
|
||||
})
|
||||
|
||||
relayHub.on('error', (err: Error) => {
|
||||
error.value = err
|
||||
isConnected.value = false
|
||||
isConnecting.value = false
|
||||
})
|
||||
|
||||
relayHub.on('connecting', () => {
|
||||
isConnecting.value = true
|
||||
})
|
||||
}
|
||||
|
||||
// Initialize relay hub listeners
|
||||
setupRelayHubListeners()
|
||||
|
||||
return {
|
||||
// State
|
||||
isConnected,
|
||||
isConnecting,
|
||||
error,
|
||||
relayUrls,
|
||||
account,
|
||||
pushSubscription,
|
||||
notificationsEnabled,
|
||||
|
||||
// Actions
|
||||
connect,
|
||||
disconnect,
|
||||
setConnected,
|
||||
setRelayUrls,
|
||||
setAccount,
|
||||
enablePushNotifications,
|
||||
disablePushNotifications,
|
||||
checkPushNotificationStatus,
|
||||
sendTestNotification,
|
||||
}
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue