Skip to main content

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 β†’