From 093846b351b45673a85eb0a9dd63bab9d31a34c9 Mon Sep 17 00:00:00 2001 From: padreug Date: Sun, 7 Sep 2025 01:42:41 +0200 Subject: [PATCH] Migrate PaymentMonitorService to dependency injection pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert PaymentMonitorService to extend BaseService with proper metadata - Add invoiceService property to BaseService for payment status checking - Register PaymentMonitorService in market module with DI container - Update market store to use injected service instead of singleton import - Remove exported singleton instance from service file - Add proper service initialization and cleanup in market module This completes the third legacy service migration, following InvoiceService and NostrmarketService. The service now properly integrates with the DI architecture for better testing, lifecycle management, and loose coupling. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- docs/.obsidian/workspace.json | 5 +- src/core/base/BaseService.ts | 2 + src/modules/market/index.ts | 17 ++++++- src/modules/market/services/paymentMonitor.ts | 48 ++++++++++++++----- src/modules/market/stores/market.ts | 7 +-- 5 files changed, 59 insertions(+), 20 deletions(-) diff --git a/docs/.obsidian/workspace.json b/docs/.obsidian/workspace.json index 74aab89..506705b 100644 --- a/docs/.obsidian/workspace.json +++ b/docs/.obsidian/workspace.json @@ -13,12 +13,12 @@ "state": { "type": "markdown", "state": { - "file": "01-architecture/index.md", + "file": "04-migrations/dependency-injection-migration.md", "mode": "source", "source": false }, "icon": "lucide-file", - "title": "index" + "title": "dependency-injection-migration" } } ] @@ -170,6 +170,7 @@ }, "active": "fe085d296b05d361", "lastOpenFiles": [ + "01-architecture/index.md", "00-overview/index.md" ] } \ No newline at end of file diff --git a/src/core/base/BaseService.ts b/src/core/base/BaseService.ts index f08ac44..812a462 100644 --- a/src/core/base/BaseService.ts +++ b/src/core/base/BaseService.ts @@ -47,6 +47,7 @@ export abstract class BaseService { protected visibilityService: any = null protected storageService: any = null protected toastService: any = null + protected invoiceService: any = null // Service state public readonly isInitialized: Ref = ref(false) @@ -138,6 +139,7 @@ export abstract class BaseService { this.visibilityService = tryInjectService(SERVICE_TOKENS.VISIBILITY_SERVICE) this.storageService = tryInjectService(SERVICE_TOKENS.STORAGE_SERVICE) this.toastService = tryInjectService(SERVICE_TOKENS.TOAST_SERVICE) + this.invoiceService = tryInjectService(SERVICE_TOKENS.INVOICE_SERVICE) // Check if all required dependencies are available const missingDeps = this.getMissingDependencies() diff --git a/src/modules/market/index.ts b/src/modules/market/index.ts index adcfb95..e18c26a 100644 --- a/src/modules/market/index.ts +++ b/src/modules/market/index.ts @@ -19,6 +19,7 @@ import { useMarketPreloader } from './composables/useMarketPreloader' // Import services import { NostrmarketService } from './services/nostrmarketService' +import { PaymentMonitorService } from './services/paymentMonitor' export interface MarketModuleConfig { defaultCurrency: string @@ -44,11 +45,14 @@ export const marketModule: ModulePlugin = { throw new Error('Market module requires configuration') } - // Create and register NostrmarketService instance + // Create and register service instances const nostrmarketService = new NostrmarketService() container.provide(SERVICE_TOKENS.NOSTRMARKET_SERVICE, nostrmarketService) - // Initialize the service (will handle dependency injection) + const paymentMonitorService = new PaymentMonitorService() + container.provide(SERVICE_TOKENS.PAYMENT_MONITOR, paymentMonitorService) + + // Initialize services (will handle dependency injection) await nostrmarketService.initialize({ waitForDependencies: true, maxRetries: 3 @@ -56,6 +60,14 @@ export const marketModule: ModulePlugin = { console.warn('🛒 NostrmarketService initialization deferred:', error) // Service will auto-initialize when dependencies are available }) + + await paymentMonitorService.initialize({ + waitForDependencies: true, + maxRetries: 3 + }).catch(error => { + console.warn('🛒 PaymentMonitorService initialization deferred:', error) + // Service will auto-initialize when dependencies are available + }) // Register global components app.component('MarketSettings', MarketSettings) @@ -75,6 +87,7 @@ export const marketModule: ModulePlugin = { // Clean up services container.remove(SERVICE_TOKENS.NOSTRMARKET_SERVICE) + container.remove(SERVICE_TOKENS.PAYMENT_MONITOR) console.log('✅ Market module uninstalled') }, diff --git a/src/modules/market/services/paymentMonitor.ts b/src/modules/market/services/paymentMonitor.ts index 4880f55..4357679 100644 --- a/src/modules/market/services/paymentMonitor.ts +++ b/src/modules/market/services/paymentMonitor.ts @@ -1,4 +1,5 @@ import { ref } from 'vue' +import { BaseService } from '@/core/base/BaseService' import type { PaymentStatus, LightningInvoice } from '@/core/services/invoiceService' import type { Order } from '@/stores/market' @@ -18,7 +19,14 @@ export interface PaymentUpdate { paidAt?: number } -class PaymentMonitorService { +export class PaymentMonitorService extends BaseService { + // Service metadata + protected readonly metadata = { + name: 'PaymentMonitorService', + version: '1.0.0', + dependencies: ['InvoiceService'] // Only depends on InvoiceService for payment status checking + } + private state = ref({ isMonitoring: false, activeInvoices: new Map(), @@ -30,6 +38,14 @@ class PaymentMonitorService { private monitoringInterval: number | null = null private updateCallbacks: Map void> = new Map() + /** + * Service-specific initialization (called by BaseService) + */ + protected async onInitialize(): Promise { + this.debug('PaymentMonitorService initialized') + // No special initialization needed + } + // Computed properties get isMonitoring() { return this.state.value.isMonitoring } get activeInvoices() { return this.state.value.activeInvoices } @@ -156,22 +172,29 @@ class PaymentMonitorService { */ private async getPaymentStatus(paymentHash: string): Promise { try { - // For now, we'll simulate payment status checking since we don't have wallet context here - // In production, this would integrate with LNBits webhooks or polling - // TODO: Pass wallet information from the order context - console.log('Payment status check requested for:', paymentHash) + // Use injected InvoiceService for payment status checking + if (!this.invoiceService) { + console.warn('InvoiceService not available, returning default pending status') + return { + paid: false, + amount_paid: 0, + payment_hash: paymentHash + } + } - // Return default pending status for now + console.log('Checking payment status for:', paymentHash) + + // TODO: Need to pass adminKey from order context - for now return pending + // In a complete implementation, we'd store wallet context with each order + // const status = await this.invoiceService.checkPaymentStatus(paymentHash, adminKey) + // return status + + // Return default pending status until wallet context is available return { paid: false, amount_paid: 0, payment_hash: paymentHash } - - // TODO: Implement when wallet context is available and PaymentMonitorService is migrated to DI: - // const invoiceService = injectService(SERVICE_TOKENS.INVOICE_SERVICE) as InvoiceService - // const status = await invoiceService.checkPaymentStatus(paymentHash, adminKey) - // return status } catch (error) { console.error('Failed to get payment status:', error) // Return default pending status @@ -271,6 +294,5 @@ class PaymentMonitorService { } } -// Export singleton instance -export const paymentMonitor = new PaymentMonitorService() +// Service is now registered in the DI container diff --git a/src/modules/market/stores/market.ts b/src/modules/market/stores/market.ts index 9b8e167..81007e9 100644 --- a/src/modules/market/stores/market.ts +++ b/src/modules/market/stores/market.ts @@ -1,6 +1,6 @@ import { defineStore } from 'pinia' import { ref, computed, readonly, watch } from 'vue' -import { paymentMonitor } from '../services/paymentMonitor' +import type { PaymentMonitorService } from '../services/paymentMonitor' import { useAuth } from '@/composables/useAuthService' import { injectService, SERVICE_TOKENS } from '@/core/di-container' import type { LightningInvoice, InvoiceService } from '@/core/services/invoiceService' @@ -19,6 +19,7 @@ export const useMarketStore = defineStore('market', () => { const storageService = injectService(SERVICE_TOKENS.STORAGE_SERVICE) as any const invoiceService = injectService(SERVICE_TOKENS.INVOICE_SERVICE) as InvoiceService const nostrmarketService = injectService(SERVICE_TOKENS.NOSTRMARKET_SERVICE) as NostrmarketService + const paymentMonitorService = injectService(SERVICE_TOKENS.PAYMENT_MONITOR) as PaymentMonitorService // Core market state const markets = ref([]) const stalls = ref([]) @@ -545,10 +546,10 @@ export const useMarketStore = defineStore('market', () => { saveOrdersToStorage() // Start monitoring payment - await paymentMonitor.startMonitoring(order, invoice) + await paymentMonitorService.startMonitoring(order, invoice) // Set up payment update callback - paymentMonitor.onPaymentUpdate(orderId, (update) => { + paymentMonitorService.onPaymentUpdate(orderId, (update) => { handlePaymentUpdate(orderId, update) })