IPC Communication
Reference for Electron IPC communication patterns.
Overviewβ
FitFileViewer uses Electron's IPC for secure main-renderer communication.
Available Channelsβ
File Operationsβ
dialog:open-fit-fileβ
Opens file selection dialog.
// Renderer
const result = await window.electronAPI.openFile();
// Main handler
ipcMain.handle("dialog:open-fit-file", async () => {
return dialog.showOpenDialog({
properties: ["openFile"],
filters: [{ name: "FIT Files", extensions: ["fit"] }],
});
});
file:readβ
Reads file contents.
// Renderer
const buffer = await window.electronAPI.readFile(filePath);
// Main handler
ipcMain.handle("file:read", async (event, filePath) => {
return fs.promises.readFile(filePath);
});
App Informationβ
app:get-versionβ
Gets application version.
// Renderer
const version = await window.electronAPI.getVersion();
// Main handler
ipcMain.handle("app:get-version", () => {
return app.getVersion();
});
Preload Scriptβ
Exposed APIβ
// preload.ts
import { contextBridge, ipcRenderer } from "electron";
contextBridge.exposeInMainWorld("electronAPI", {
// File operations
openFile: () => ipcRenderer.invoke("dialog:open-fit-file"),
readFile: (path) => ipcRenderer.invoke("file:read", path),
// App info
getVersion: () => ipcRenderer.invoke("app:get-version"),
// Events
onFileOpened: (callback) => {
ipcRenderer.on("file:opened", (event, data) => callback(data));
},
});
Event Communicationβ
Main β Rendererβ
// Main process
mainWindow.webContents.send("file:opened", {
path: filePath,
data: fileData,
});
// Renderer (via preload)
window.electronAPI.onFileOpened((data) => {
console.log("File opened:", data.path);
});
Renderer β Mainβ
// Renderer
const result = await window.electronAPI.openFile();
// Main
ipcMain.handle("dialog:open-fit-file", async (event) => {
// Handle request
return result;
});
Security Considerationsβ
Input Validationβ
// Always validate in main process
ipcMain.handle("file:read", async (event, filePath) => {
// Validate path
if (typeof filePath !== "string") {
throw new Error("Invalid path type");
}
// Validate extension
if (!filePath.endsWith(".fit")) {
throw new Error("Invalid file type");
}
// Validate path traversal
const normalized = path.normalize(filePath);
if (normalized.includes("..")) {
throw new Error("Path traversal detected");
}
return fs.promises.readFile(normalized);
});
Limited Exposureβ
Only expose necessary functions:
// β Bad: Exposes too much
ipcRenderer: ipcRenderer, // Full access
// β
Good: Specific functions only
openFile: () => ipcRenderer.invoke('dialog:open-fit-file'),
Next: State Management β