You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

146 lines
5.5 KiB

import { initializeApp } from "./main.common";
import { logger } from "./utils/logger";
const platform = process.env.VITE_PLATFORM;
const pwa_enabled = process.env.VITE_PWA_ENABLED === "true";
logger.info("[Main Electron] Initializing app");
logger.info("[Main Electron] Platform:", { platform });
logger.info("[Main Electron] PWA enabled:", { pwa_enabled });
if (pwa_enabled) {
logger.warn("[Main Electron] PWA is enabled, but not supported in electron");
}
// Initialize app and SQLite
const app = initializeApp();
/**
* SQLite initialization configuration
* Defines timeouts and retry settings for database operations
*
* @author Matthew Raymer
*/
const SQLITE_CONFIG = {
INITIALIZATION: {
TIMEOUT_MS: 10000, // 10 seconds for initial setup
RETRY_ATTEMPTS: 3,
RETRY_DELAY_MS: 1000
},
OPERATIONS: {
TIMEOUT_MS: 5000, // 5 seconds for regular operations
RETRY_ATTEMPTS: 2,
RETRY_DELAY_MS: 500
},
CONNECTION: {
MAX_CONNECTIONS: 5,
IDLE_TIMEOUT_MS: 30000
}
};
// Create a promise that resolves when SQLite is ready
const sqliteReady = new Promise<void>((resolve, reject) => {
let retryCount = 0;
let initializationTimeout: NodeJS.Timeout;
const attemptInitialization = () => {
// Clear any existing timeout
if (initializationTimeout) {
clearTimeout(initializationTimeout);
}
// Set timeout for this attempt
initializationTimeout = setTimeout(() => {
if (retryCount < SQLITE_CONFIG.INITIALIZATION.RETRY_ATTEMPTS) {
retryCount++;
logger.warn(`[Main Electron] SQLite initialization attempt ${retryCount} timed out, retrying...`);
setTimeout(attemptInitialization, SQLITE_CONFIG.INITIALIZATION.RETRY_DELAY_MS);
} else {
logger.error("[Main Electron] SQLite initialization failed after all retries");
reject(new Error("SQLite initialization timeout after all retries"));
}
}, SQLITE_CONFIG.INITIALIZATION.TIMEOUT_MS);
// Wait for electron bridge to be available
const checkElectronBridge = () => {
if (window.electron?.ipcRenderer) {
logger.info("[Main Electron] IPC renderer bridge available");
// Listen for SQLite ready signal
window.electron.ipcRenderer.once('sqlite-ready', () => {
clearTimeout(initializationTimeout);
logger.info("[Main Electron] Received SQLite ready signal");
resolve();
});
// Also listen for database errors
window.electron.ipcRenderer.once('database-status', (...args: unknown[]) => {
clearTimeout(initializationTimeout);
const status = args[0] as { status: string; error?: string };
if (status.status === 'error') {
logger.error("[Main Electron] Database error:", status.error);
reject(new Error(status.error || 'Database initialization failed'));
}
});
// Check if SQLite is already available
window.electron.ipcRenderer.invoke('sqlite-is-available')
.then((result: unknown) => {
const isAvailable = Boolean(result);
if (isAvailable) {
logger.info("[Main Electron] SQLite is already available");
// Don't resolve here - wait for the ready signal
// This prevents race conditions where the ready signal arrives after this check
}
})
.catch((error: Error) => {
logger.error("[Main Electron] Failed to check SQLite availability:", error);
// Don't reject here - wait for either ready signal or timeout
});
} else {
// Check again in 100ms if bridge isn't ready
setTimeout(checkElectronBridge, 100);
}
};
// Start checking for bridge
checkElectronBridge();
};
// Start first initialization attempt
attemptInitialization();
});
// Wait for SQLite to be ready before mounting
sqliteReady
.then(() => {
logger.info("[Main Electron] SQLite ready, mounting app...");
app.mount("#app");
logger.info("[Main Electron] App mounted successfully");
})
.catch((error) => {
logger.error("[Main Electron] Failed to initialize SQLite:", error instanceof Error ? error.message : 'Unknown error');
// Show error to user with retry option
const errorDiv = document.createElement("div");
errorDiv.style.cssText =
"position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #ffebee; color: #c62828; padding: 20px; border-radius: 4px; text-align: center; max-width: 80%; z-index: 9999;";
errorDiv.innerHTML = `
<h2>Failed to Initialize Application</h2>
<p>There was an error initializing the database. This could be due to:</p>
<ul style="text-align: left; margin: 10px 0;">
<li>Database file is locked by another process</li>
<li>Insufficient permissions to access the database</li>
<li>Database file is corrupted</li>
</ul>
<p>Error details: ${error instanceof Error ? error.message : 'Unknown error'}</p>
<div style="margin-top: 15px;">
<button onclick="window.location.reload()" style="margin: 0 5px; padding: 8px 16px; background: #c62828; color: white; border: none; border-radius: 4px; cursor: pointer;">
Retry
</button>
<button onclick="window.electron.ipcRenderer.send('sqlite-status', { action: 'reset' })" style="margin: 0 5px; padding: 8px 16px; background: #f57c00; color: white; border: none; border-radius: 4px; cursor: pointer;">
Reset Database
</button>
</div>
`;
document.body.appendChild(errorDiv);
});