Files
sf-nfc-reader-desktop/src/main/index.ts
2026-03-17 12:40:03 +01:00

146 lines
4.7 KiB
TypeScript

import { app, shell, BrowserWindow, ipcMain } from "electron";
import { join } from "path";
import { electronApp, optimizer, is } from "@electron-toolkit/utils";
import icon from "../../resources/icon.png?asset";
import { NfcService } from "../services/NfcService";
import { labelReqHandler, printReqHandler } from "./handlers";
import { logger } from "./LogService";
import { createConnection } from "net";
function createWindow(): void {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 900,
height: 670,
show: false,
autoHideMenuBar: true,
...(process.platform === "linux" ? { icon } : {}),
webPreferences: {
preload: join(__dirname, "../preload/index.js"),
sandbox: false,
},
});
const nfcService = new NfcService((event) => {
if (!mainWindow.isDestroyed()) {
mainWindow.webContents.send(`nfc:${event.type}`, event);
}
});
ipcMain.handle("nfc:getReaderName", () => {
return nfcService.getReaderName();
});
mainWindow.on("ready-to-show", () => {
mainWindow.show();
});
mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url);
return { action: "deny" };
});
// HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production.
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
mainWindow.loadURL(process.env["ELECTRON_RENDERER_URL"]);
} else {
mainWindow.loadFile(join(__dirname, "../renderer/index.html"));
}
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
// Set app user model id for windows
electronApp.setAppUserModelId("com.electron");
// Default open or close DevTools by F12 in development
// and ignore CommandOrControl + R in production.
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
app.on("browser-window-created", (_, window) => {
optimizer.watchWindowShortcuts(window);
});
// IPC test
ipcMain.on("ping", () => console.log("pong"));
// HANDLE es bidireccionar ON es unidireccional
/**
* LLamada principal
* Cli - card_id -> Server - etiqueta/activacion -> Cli
*/
ipcMain.handle("nfc:labelReq", labelReqHandler);
ipcMain.handle("nfc:printReq", printReqHandler);
ipcMain.handle("ping:url", async (_event, url: string) => {
try {
const response = await fetch(url, {
method: "HEAD",
signal: AbortSignal.timeout(5000),
});
return response.ok;
} catch (error) {
console.error(`Ping failed for ${url}:`, error);
return false;
}
});
ipcMain.handle(
"ping:socket",
async (_event, data: { ip: string; port: number }) => {
return new Promise((req, rej) => {
const { ip, port } = data;
let finished = false;
console.log("Pinging,", ip, port);
const socket = createConnection(port, ip);
socket.setTimeout(3 * 1000);
socket.on("connect", (e) => {
console.log("Conectado!", e);
logger.info("Printer connected, sending label...");
socket.end();
finished = true;
req(true);
});
socket.on("timeout", (err) => {
if (finished) return;
finished = true;
socket.destroy();
rej(false);
});
socket.on("error", (err) => {
if (finished) return;
finished = true;
socket.destroy();
rej(false);
});
});
},
);
createWindow();
app.on("activate", function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.