Refactor services to extend BaseService for improved structure and dependency management

- Update AuthService and RelayHub to extend BaseService, introducing standardized initialization and metadata handling.
- Implement service-specific initialization methods in both services, enhancing error handling and logging.
- Modify NostrmarketService to inherit from BaseService, ensuring consistent dependency management and initialization.
- Refactor market module to dynamically import NostrmarketService, improving service registration and initialization flow.
- Enhance debug logging across services for better traceability during initialization and operation.
This commit is contained in:
padreug 2025-09-05 06:41:19 +02:00
parent 8d4c389f71
commit dc4da570a7
5 changed files with 151 additions and 50 deletions

View file

@ -1,15 +1,27 @@
// Auth service for LNbits integration
import { ref } from 'vue'
import { BaseService } from '@/core/base/BaseService'
import { eventBus } from '@/core/event-bus'
import { lnbitsAPI, type LoginCredentials, type RegisterData } from '@/lib/api/lnbits'
export class AuthService {
export class AuthService extends BaseService {
// Service metadata
protected readonly metadata = {
name: 'AuthService',
version: '1.0.0',
dependencies: [] // Auth service has no dependencies on other services
}
// Public state
public isAuthenticated = ref(false)
public user = ref<any>(null)
public isLoading = ref(false)
async initialize(): Promise<void> {
console.log('🔑 Initializing auth service...')
/**
* Service-specific initialization (called by BaseService)
*/
protected async onInitialize(): Promise<void> {
this.debug('Initializing auth service...')
// Check for existing auth state and fetch user data
await this.checkAuth()
@ -21,7 +33,7 @@ export class AuthService {
async checkAuth(): Promise<boolean> {
if (!lnbitsAPI.isAuthenticated()) {
console.log('🔑 No auth token found - user needs to login')
this.debug('No auth token found - user needs to login')
this.isAuthenticated.value = false
this.user.value = null
return false
@ -34,12 +46,12 @@ export class AuthService {
this.user.value = userData
this.isAuthenticated.value = true
console.log('🔑 User authenticated:', userData.username || userData.id, userData.pubkey?.slice(0, 8))
this.debug(`User authenticated: ${userData.username || userData.id} (${userData.pubkey?.slice(0, 8)})`)
return true
} catch (error) {
console.warn('🔑 Authentication check failed:', error)
this.handleError(error, 'checkAuth')
this.isAuthenticated.value = false
this.user.value = null
// Clear invalid token
@ -63,9 +75,9 @@ export class AuthService {
eventBus.emit('auth:login', { user: userData }, 'auth-service')
} catch (error) {
console.error('Login failed:', error)
eventBus.emit('auth:login-failed', { error }, 'auth-service')
throw error
const err = this.handleError(error, 'login')
eventBus.emit('auth:login-failed', { error: err }, 'auth-service')
throw err
} finally {
this.isLoading.value = false
}
@ -84,9 +96,9 @@ export class AuthService {
eventBus.emit('auth:login', { user: userData }, 'auth-service')
} catch (error) {
console.error('Registration failed:', error)
eventBus.emit('auth:login-failed', { error }, 'auth-service')
throw error
const err = this.handleError(error, 'register')
eventBus.emit('auth:login-failed', { error: err }, 'auth-service')
throw err
} finally {
this.isLoading.value = false
}
@ -104,6 +116,14 @@ export class AuthService {
// Re-fetch user data from API
await this.checkAuth()
}
/**
* Cleanup when service is disposed
*/
protected async onDispose(): Promise<void> {
this.logout()
this.debug('Auth service disposed')
}
}
// Export singleton instance

View file

@ -33,7 +33,10 @@ export const baseModule: ModulePlugin = {
// Initialize core services
await relayHub.initialize(options?.config?.nostr?.relays || [])
await auth.initialize()
await auth.initialize({
waitForDependencies: false, // Auth has no dependencies
maxRetries: 1
})
console.log('✅ Base module installed successfully')
},

View file

@ -1,4 +1,6 @@
import { SimplePool, type Filter, type Event, type Relay } from 'nostr-tools'
import { BaseService } from '@/core/base/BaseService'
import { ref } from 'vue'
// Simple EventEmitter implementation for browser compatibility
class EventEmitter {
@ -57,17 +59,29 @@ export interface RelayStatus {
latency?: number
}
export class RelayHub extends EventEmitter {
export class RelayHub extends BaseService {
// Service metadata
protected readonly metadata = {
name: 'RelayHub',
version: '1.0.0',
dependencies: [] // RelayHub has no dependencies on other services
}
// EventEmitter functionality
private eventEmitter = new EventEmitter()
// RelayHub specific properties
private pool: SimplePool
private relayConfigs: Map<string, RelayConfig> = new Map()
private connectedRelays: Map<string, Relay> = new Map()
private subscriptions: Map<string, any> = new Map()
public isInitialized = false
public isInitializedLegacy = false // Keep for backward compatibility
private reconnectInterval?: number
private healthCheckInterval?: number
private mobileVisibilityHandler?: () => void
// Connection state
// Connection state - we need both a reactive ref for components and internal state for business logic
public isConnected = ref(false)
private _isConnected = false
private _connectionAttempts = 0
private readonly maxReconnectAttempts = 5
@ -79,10 +93,24 @@ export class RelayHub extends EventEmitter {
this.pool = new SimplePool()
this.setupMobileVisibilityHandling()
}
get isConnected(): boolean {
return this._isConnected
// Forward EventEmitter methods
on(event: string, listener: Function): void {
this.eventEmitter.on(event, listener)
}
off(event: string, listener: Function): void {
this.eventEmitter.off(event, listener)
}
emit(event: string, ...args: any[]): void {
this.eventEmitter.emit(event, ...args)
}
removeAllListeners(event?: string): void {
this.eventEmitter.removeAllListeners(event)
}
get connectedRelayCount(): number {
// Return the actual size of connectedRelays map
@ -123,14 +151,38 @@ export class RelayHub extends EventEmitter {
/**
* Initialize the relay hub with relay configurations
* This is the public API that maintains backward compatibility
*/
async initialize(relayUrls: string[]): Promise<void> {
if (this.isInitialized) {
console.warn('RelayHub already initialized')
return
async initialize(relayUrls: string[]): Promise<void>
async initialize(options: any): Promise<void>
async initialize(relayUrlsOrOptions: string[] | any): Promise<void> {
// Handle backward compatibility for relayUrls array
if (Array.isArray(relayUrlsOrOptions)) {
this.pendingRelayUrls = relayUrlsOrOptions
// Use BaseService's initialize method
await super.initialize({
waitForDependencies: false, // RelayHub has no dependencies
maxRetries: 1
})
} else {
// This is a call from BaseService or other services
await super.initialize(relayUrlsOrOptions)
}
console.log('🔧 RelayHub: Initializing with URLs:', relayUrls)
}
private pendingRelayUrls: string[] = []
/**
* Service-specific initialization (called by BaseService)
*/
protected async onInitialize(): Promise<void> {
const relayUrls = this.pendingRelayUrls
if (!relayUrls || relayUrls.length === 0) {
throw new Error('No relay URLs provided for initialization')
}
this.debug(`Initializing with URLs: ${relayUrls.join(', ')}`)
// Convert URLs to relay configs
this.relayConfigs.clear()
@ -143,14 +195,14 @@ export class RelayHub extends EventEmitter {
})
})
console.log('🔧 RelayHub: Relay configs created:', Array.from(this.relayConfigs.values()))
this.debug(`Relay configs created: ${this.relayConfigs.size} configs`)
// Start connection management
console.log('🔧 RelayHub: Starting connection...')
this.debug('Starting connection...')
await this.connect()
this.startHealthCheck()
this.isInitialized = true
console.log('🔧 RelayHub: Initialization complete')
this.isInitializedLegacy = true // Keep for backward compatibility
this.debug('Initialization complete')
}
/**
@ -200,6 +252,7 @@ export class RelayHub extends EventEmitter {
if (successfulConnections.length > 0) {
this._isConnected = true
this.isConnected.value = true
this._connectionAttempts = 0
console.log('🔧 RelayHub: Connection successful, connected to', successfulConnections.length, 'relays')
this.emit('connected', successfulConnections.length)
@ -210,6 +263,7 @@ export class RelayHub extends EventEmitter {
}
} catch (error) {
this._isConnected = false
this.isConnected.value = false
console.error('🔧 RelayHub: Connection failed with error:', error)
this.emit('connectionError', error)
@ -228,8 +282,6 @@ export class RelayHub extends EventEmitter {
* Disconnect from all relays
*/
disconnect(): void {
// Clear intervals
if (this.reconnectInterval) {
clearTimeout(this.reconnectInterval)
@ -250,6 +302,7 @@ export class RelayHub extends EventEmitter {
this.connectedRelays.clear()
this._isConnected = false
this.isConnected.value = false
this.emit('disconnected')
}
@ -448,6 +501,7 @@ export class RelayHub extends EventEmitter {
// Update connection status
if (this.connectedRelays.size === 0) {
this._isConnected = false
this.isConnected.value = false
this.emit('allRelaysDisconnected')
console.warn('All relays disconnected, attempting reconnection...')
await this.connect()
@ -489,6 +543,7 @@ export class RelayHub extends EventEmitter {
window.addEventListener('offline', () => {
console.log('Network offline, marking as disconnected...')
this._isConnected = false
this.isConnected.value = false
this.emit('networkOffline')
})
}
@ -498,8 +553,13 @@ export class RelayHub extends EventEmitter {
* Cleanup resources
*/
destroy(): void {
this.dispose()
}
/**
* Cleanup when service is disposed (called by BaseService)
*/
protected async onDispose(): Promise<void> {
// Remove event listeners
if (this.mobileVisibilityHandler && typeof document !== 'undefined') {
document.removeEventListener('visibilitychange', this.mobileVisibilityHandler)
@ -513,7 +573,9 @@ export class RelayHub extends EventEmitter {
// Disconnect and cleanup
this.disconnect()
this.removeAllListeners()
this.isInitialized = false
this.isInitializedLegacy = false
this.debug('RelayHub disposed')
}
}