Files
IPSExtractor/services/desktop_app/electron/main.cjs
T

166 lines
4.8 KiB
JavaScript

const { app, BrowserWindow, dialog, ipcMain } = require("electron");
const fs = require("node:fs/promises");
const path = require("node:path");
const { indexFolder } = require("./folderIndex.cjs");
const autoUpdate = require("./autoUpdate.cjs");
const { version: appVersion } = require("../package.json");
const DOCUMENT_EXTENSIONS = new Set([".pdf", ".tif", ".tiff", ".png", ".jpg", ".jpeg"]);
const APP_ICON = path.join(__dirname, "icon.png");
/** @type {BrowserWindow | null} */
let mainWindow = null;
function createWindow() {
const win = new BrowserWindow({
width: 1280,
height: 860,
minWidth: 1080,
minHeight: 720,
title: `IPSExtractor Desktop v${appVersion}`,
icon: APP_ICON,
backgroundColor: "#f6f7f9",
webPreferences: {
preload: path.join(__dirname, "preload.cjs"),
contextIsolation: true,
nodeIntegration: false,
},
});
mainWindow = win;
win.on("closed", () => {
if (mainWindow === win) mainWindow = null;
});
if (!app.isPackaged) {
win.loadURL("http://127.0.0.1:5173");
win.webContents.openDevTools({ mode: "detach" });
} else {
win.loadFile(path.join(app.getAppPath(), "dist", "index.html"));
}
}
function sendUpdateProgress(payload) {
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send("updater:progress", payload);
}
}
ipcMain.handle("updater:check", async () => {
return autoUpdate.checkForUpdates();
});
ipcMain.handle("updater:release-meta", async () => {
return autoUpdate.getCurrentReleaseMeta();
});
ipcMain.handle("updater:list-versions", async () => {
return autoUpdate.listVersions();
});
ipcMain.handle("updater:install", async (_event, manifest) => {
if (!app.isPackaged) {
throw new Error("Instalar actualizaciones solo está disponible en la app instalada");
}
return autoUpdate.downloadAndInstall(manifest, sendUpdateProgress);
});
app.whenReady().then(() => {
if (process.platform === "win32") {
app.setAppUserModelId("com.ipsextractor.desktop");
}
createWindow();
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit();
});
ipcMain.handle("dialog:select-directory", async () => {
const result = await dialog.showOpenDialog({
properties: ["openDirectory"],
});
if (result.canceled || result.filePaths.length === 0) return null;
return result.filePaths[0];
});
ipcMain.handle("runtime:config", async () => {
return {
documentRootLocal: process.env.IPS_DOCUMENT_ROOT || "",
documentRootContainer: process.env.IPS_DOCUMENT_ROOT_CONTAINER || "/data",
};
});
ipcMain.handle("dialog:save-csv", async (_event, defaultPath) => {
const result = await dialog.showSaveDialog({
defaultPath: defaultPath || "extraccion.csv",
filters: [{ name: "CSV", extensions: ["csv"] }],
});
if (result.canceled || !result.filePath) return null;
return result.filePath;
});
ipcMain.handle("file:write-text", async (_event, filePath, content) => {
await fs.writeFile(filePath, content, "utf8");
return { ok: true, filePath };
});
ipcMain.handle("fs:first-document", async (_event, rootPath, keywords) => {
const matches = await findDocuments(rootPath, Array.isArray(keywords) ? keywords : []);
return matches[0] || null;
});
ipcMain.handle("fs:index-folder", async (_event, rootPath, structureMode, docTypes, keywords) => {
if (!rootPath) return [];
return indexFolder(rootPath, structureMode, Array.isArray(docTypes) ? docTypes : [], Array.isArray(keywords) ? keywords : []);
});
ipcMain.handle("fs:read-file", async (_event, filePath) => {
const buffer = await fs.readFile(filePath);
return {
filename: path.basename(filePath),
size: buffer.byteLength,
data: buffer,
};
});
async function findDocuments(rootPath, keywords) {
const normalizedKeywords = keywords
.map((item) => String(item || "").trim().toLowerCase())
.filter(Boolean);
const out = [];
async function walk(dir) {
let entries;
try {
entries = await fs.readdir(dir, { withFileTypes: true });
} catch {
return;
}
entries.sort((a, b) => a.name.localeCompare(b.name, undefined, { numeric: true }));
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
await walk(fullPath);
if (out.length > 0) return;
continue;
}
const ext = path.extname(entry.name).toLowerCase();
if (!DOCUMENT_EXTENSIONS.has(ext)) continue;
const lowerName = entry.name.toLowerCase();
if (normalizedKeywords.length > 0 && !normalizedKeywords.some((kw) => lowerName.includes(kw))) {
continue;
}
out.push(fullPath);
return;
}
}
await walk(rootPath);
return out;
}