From 9eb07b3258f718c62f7cddb46b6eefaee4fa7054 Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Thu, 5 Jun 2025 08:44:42 +0000 Subject: [PATCH] fix: improve API server update reliability and logging - Refactor dbExec in ElectronPlatformService to use proper connection management - Add comprehensive logging throughout API server update flow - Fix connection handling in database operations - Add user feedback notifications for success/failure - Add verification step after settings update The main issue was that dbExec wasn't using the same robust connection management as dbQuery, leading to "SQLite not initialized" errors. Now both methods use the same connection lifecycle management through enqueueOperation. Also added detailed logging at each step to help diagnose any future issues: - AccountViewView component logging - Database utility operations logging - Connection state tracking - Update verification This should make the API server update more reliable and easier to debug. --- electron/src/rt/sqlite-init.ts | 8 +-- .../platforms/ElectronPlatformService.ts | 41 ++++++++----- src/views/AccountViewView.vue | 59 +++++++++++++++++-- 3 files changed, 83 insertions(+), 25 deletions(-) diff --git a/electron/src/rt/sqlite-init.ts b/electron/src/rt/sqlite-init.ts index 69c4c4b2..16468208 100644 --- a/electron/src/rt/sqlite-init.ts +++ b/electron/src/rt/sqlite-init.ts @@ -268,8 +268,8 @@ const verifyTransactionState = async (database: string): Promise => { // Only update state if it's different if (isActive !== transactionState.isActive || transactionState.database !== database) { - transactionState.isActive = isActive; - transactionState.lastVerified = new Date(); + transactionState.isActive = isActive; + transactionState.lastVerified = new Date(); transactionState.database = isActive ? database : null; } @@ -526,7 +526,7 @@ export async function initializeSQLite(): Promise { try { logger.debug('Executing PRAGMA:', statement); const result = await pluginState.instance.execute({ - database: connectionOptions.database, + database: connectionOptions.database, statements: statement, transaction: false }); @@ -900,7 +900,7 @@ export function setupSQLiteHandlers(): void { }); logger.info('SQLite IPC handlers setup complete'); -} +} // Update transaction management to be more careful const beginTransaction = async (database: string): Promise => { diff --git a/src/services/platforms/ElectronPlatformService.ts b/src/services/platforms/ElectronPlatformService.ts index 357c69c4..d7b43e58 100644 --- a/src/services/platforms/ElectronPlatformService.ts +++ b/src/services/platforms/ElectronPlatformService.ts @@ -691,24 +691,35 @@ export class ElectronPlatformService implements PlatformService { sql: string, params?: unknown[], ): Promise<{ changes: number; lastId?: number }> { - await this.initializeDatabase(); if (this.dbFatalError) { - throw new Error( - "Database is in a fatal error state. Please restart the app.", - ); - } - if (!this.sqlite) { - throw new Error("SQLite not initialized"); + throw new Error("Database is in a fatal error state. Please restart the app."); } - const result = await this.sqlite.run({ - database: this.dbName, - statement: sql, - values: params, + + return this.enqueueOperation(async () => { + try { + // Get connection (will wait for existing connection if any) + await this.getConnection(); + + // Execute query + const result = await window.electron!.ipcRenderer.invoke('sqlite-run', { + database: this.dbName, + statement: sql, + values: params + }) as SQLiteQueryResult; + logger.debug("[ElectronPlatformService] [dbExec] Query executed successfully"); + + return { + changes: result.changes?.changes || 0, + lastId: result.changes?.lastId, + }; + } catch (error) { + logger.error("[ElectronPlatformService] [dbExec] Query failed:", error); + throw error; + } finally { + // Release connection after query + await this.releaseConnection(); + } }); - return { - changes: result.changes?.changes || 0, - lastId: result.changes?.lastId, - }; } async initialize(): Promise { diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index 22f342f1..56265545 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -1886,16 +1886,63 @@ export default class AccountViewView extends Vue { } async onClickSaveApiServer() { - await databaseUtil.updateDefaultSettings({ - apiServer: this.apiServerInput, + logger.debug("[AccountViewView] Starting API server update", { + current: this.apiServer, + new: this.apiServerInput, + component: 'AccountViewView' }); - if (USE_DEXIE_DB) { - await db.open(); - await db.settings.update(MASTER_SETTINGS_KEY, { + + try { + logger.debug("[AccountViewView] Calling updateDefaultSettings"); + await databaseUtil.updateDefaultSettings({ apiServer: this.apiServerInput, }); + logger.debug("[AccountViewView] updateDefaultSettings completed"); + + if (USE_DEXIE_DB) { + logger.debug("[AccountViewView] Updating Dexie DB"); + await db.open(); + await db.settings.update(MASTER_SETTINGS_KEY, { + apiServer: this.apiServerInput, + }); + logger.debug("[AccountViewView] Dexie DB update completed"); + } + + this.apiServer = this.apiServerInput; + logger.debug("[AccountViewView] Local state updated", { apiServer: this.apiServer }); + + // Verify the update + const settings = await databaseUtil.retrieveSettingsForActiveAccount(); + logger.debug("[AccountViewView] Settings verification", { + retrieved: settings.apiServer, + expected: this.apiServerInput, + match: settings.apiServer === this.apiServerInput + }); + + // Show success notification + this.$notify({ + group: "alert", + type: "success", + title: "API Server Updated", + text: "API server settings saved successfully.", + }, 3000); + + } catch (error) { + logger.error("[AccountViewView] API server update failed", { + error, + current: this.apiServer, + attempted: this.apiServerInput + }); + this.$notify( + { + group: "alert", + type: "danger", + title: "Error Saving API Server", + text: "Failed to save API server settings. Please try again.", + }, + 5000, + ); } - this.apiServer = this.apiServerInput; } async onClickSavePartnerServer() {