timesafari
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.
 
 
 

172 lines
5.9 KiB

/**
* @fileoverview Electron Platform Service Implementation
* @author Matthew Raymer
*
* Provides platform-specific functionality for Electron desktop applications.
* This service extends CapacitorPlatformService to leverage Capacitor's APIs
* while overriding desktop-specific behaviors.
*
* Key Features:
* - Desktop-specific capabilities configuration
* - Native IPC-based file operations with proper security
* - Direct saving to user's Downloads folder via main process
* - Native desktop integration support
*
* Architecture:
* - Extends CapacitorPlatformService for API compatibility
* - Overrides methods for desktop-specific implementations
* - Maintains cross-platform service interface
*
* @since 1.0.0
*/
import { CapacitorPlatformService } from "./CapacitorPlatformService";
import { logger } from "../../utils/logger";
/**
* Electron-specific platform service implementation.
*
* This service handles the unique requirements of the Electron platform:
* - Desktop-specific capabilities and UI patterns
* - File system operations using Capacitor's Filesystem API
* - Native desktop integration features
* - Proper error handling with web fallbacks
*
* @extends CapacitorPlatformService
* @example
* ```typescript
* const electronService = new ElectronPlatformService();
* await electronService.writeAndShareFile('backup.json', jsonData);
* ```
*/
export class ElectronPlatformService extends CapacitorPlatformService {
/**
* Gets the capabilities of the Electron platform.
* Overrides the mobile-focused capabilities from CapacitorPlatformService
* to provide desktop-specific feature flags.
*
* @returns Platform capabilities object specific to Electron
*/
getCapabilities() {
return {
hasFileSystem: true,
hasCamera: false, // Desktop typically doesn't have integrated cameras for our use case
isMobile: false, // Electron is desktop, not mobile
isIOS: false,
hasFileDownload: true, // Desktop supports direct file downloads
needsFileHandlingInstructions: false, // Desktop users are familiar with file handling
isNativeApp: true, // Electron is a native app
};
}
/**
* Handles file export for Electron platform using native IPC.
*
* This method provides a secure, native file export mechanism that:
* 1. Uses Electron's IPC (Inter-Process Communication) for secure file operations
* 2. Writes files directly to the user's Downloads folder via the main process
* 3. Provides exact file path feedback and proper error handling
* 4. Falls back to web-style downloads if IPC is unavailable
*
* @param fileName - The name of the file to save (with date stamp)
* @param content - The content to write to the file
* @returns Promise that resolves when the file is successfully saved
* @throws {Error} If both native IPC and fallback mechanisms fail
*
* @example
* ```typescript
* await electronService.writeAndShareFile('TimeSafari-backup-contacts-2025-07-06.json', jsonData);
* ```
*
* @note This implementation follows Electron's security best practices by:
* - Using contextBridge to expose safe IPC methods
* - Handling file operations in the main process with full filesystem access
* - Providing exact file paths for better user experience
* - Maintaining secure separation between renderer and main processes
*/
async writeAndShareFile(fileName: string, content: string): Promise<void> {
logger.info(
`[ElectronPlatformService] Using native IPC for reliable file export: ${fileName}`,
);
try {
// Check if we're running in Electron with the API available
if (typeof window !== "undefined" && window.electronAPI) {
// Use the native Electron IPC API for file exports
const result = await window.electronAPI.exportData(fileName, content);
if (result.success) {
logger.info(
`[ElectronPlatformService] File exported successfully to: ${result.path}`,
);
logger.info(
`[ElectronPlatformService] File saved to Downloads folder: ${fileName}`,
);
} else {
logger.error(
`[ElectronPlatformService] Native export failed: ${result.error}`,
);
throw new Error(`Native file export failed: ${result.error}`);
}
} else {
// Fallback to web-style download if Electron API is not available
logger.warn(
"[ElectronPlatformService] Electron API not available, falling back to web download",
);
const blob = new Blob([content], { type: "application/json" });
const url = URL.createObjectURL(blob);
const downloadLink = document.createElement("a");
downloadLink.href = url;
downloadLink.download = fileName;
downloadLink.style.display = "none";
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
setTimeout(() => URL.revokeObjectURL(url), 1000);
logger.info(
`[ElectronPlatformService] Fallback download initiated: ${fileName}`,
);
}
} catch (error) {
logger.error("[ElectronPlatformService] File export failed:", error);
throw new Error(`Failed to export file: ${error}`);
}
}
/**
* Checks if running on Electron platform.
*
* @returns true, as this is the Electron implementation
*/
isElectron(): boolean {
return true;
}
/**
* Checks if running on Capacitor platform.
*
* @returns false, as this is Electron, not pure Capacitor
*/
isCapacitor(): boolean {
return false;
}
/**
* Checks if running on web platform.
*
* @returns false, as this is not web
*/
isWeb(): boolean {
return false;
}
// --- PWA/Web-only methods (no-op for Electron) ---
public registerServiceWorker(): void {}
public get isPWAEnabled(): boolean {
return false;
}
}