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:
padreug 2025-09-06 10:55:10 +02:00
parent 92c33aa0a3
commit 7e4b64b831
8 changed files with 7 additions and 661 deletions

View file

@ -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

View file

@ -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'

View file

@ -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