Jelajahi Sumber

Refactor the init process

Manav Rathi 1 tahun lalu
induk
melakukan
cb33b6df10

+ 6 - 6
desktop/src/main.ts

@@ -15,12 +15,9 @@ import { existsSync } from "node:fs";
 import fs from "node:fs/promises";
 import path from "node:path";
 import { isDev } from "./main/general";
-import { attachFSWatchIPCHandlers, attachIPCHandlers } from "./main/ipc";
-import { logErrorSentry, setupLogging } from "./main/log";
-import { initWatcher } from "./services/chokidar";
-import { addAllowOriginHeader } from "./utils/cors";
-import { createWindow } from "./utils/createWindow";
 import {
+    addAllowOriginHeader,
+    createWindow,
     handleDockIconHideOnAutoLaunch,
     handleDownloads,
     handleExternalLinks,
@@ -29,7 +26,10 @@ import {
     setupMacWindowOnDockIconClick,
     setupMainMenu,
     setupTrayItem,
-} from "./utils/main";
+} from "./main/init";
+import { attachFSWatchIPCHandlers, attachIPCHandlers } from "./main/ipc";
+import { logErrorSentry, setupLogging } from "./main/log";
+import { initWatcher } from "./services/chokidar";
 
 let appIsQuitting = false;
 

+ 254 - 0
desktop/src/main/init.ts

@@ -0,0 +1,254 @@
+import { app, BrowserWindow, Menu, nativeImage, Tray } from "electron";
+import ElectronLog from "electron-log";
+import { existsSync } from "node:fs";
+import os from "os";
+import path from "path";
+import util from "util";
+import { isAppQuitting, rendererURL } from "../main";
+import { setupAutoUpdater } from "../services/appUpdater";
+import autoLauncher from "../services/autoLauncher";
+import { getHideDockIconPreference } from "../services/userPreference";
+import { isPlatform } from "../utils/common/platform";
+import { buildContextMenu, buildMenuBar } from "../utils/menu";
+import { isDev } from "./general";
+import { logErrorSentry } from "./log";
+const execAsync = util.promisify(require("child_process").exec);
+
+/**
+ * Create an return the {@link BrowserWindow} that will form our app's UI.
+ *
+ * This window will show the HTML served from {@link rendererURL}.
+ */
+export const createWindow = async () => {
+    console.log({ __dirname });
+    const appImgPath = isDev
+        ? "resources/window-icon.png"
+        : path.join(process.resourcesPath, "window-icon.png");
+    const appIcon = nativeImage.createFromPath(appImgPath);
+    // Create the browser window.
+    const mainWindow = new BrowserWindow({
+        webPreferences: {
+            preload: path.join(__dirname, "../preload.js"),
+        },
+        icon: appIcon,
+        show: false, // don't show the main window on load,
+    });
+    const wasAutoLaunched = await autoLauncher.wasAutoLaunched();
+    ElectronLog.log("wasAutoLaunched", wasAutoLaunched);
+
+    const splash = new BrowserWindow({
+        transparent: true,
+        show: false,
+    });
+    if (isPlatform("mac") && wasAutoLaunched) {
+        app.dock.hide();
+    }
+    if (!wasAutoLaunched) {
+        splash.maximize();
+        splash.show();
+    }
+
+    if (isDev) {
+        splash.loadFile(`../build/splash.html`);
+        mainWindow.loadURL(rendererURL);
+        // Open the DevTools.
+        mainWindow.webContents.openDevTools();
+    } else {
+        splash.loadURL(
+            `file://${path.join(process.resourcesPath, "splash.html")}`,
+        );
+        mainWindow.loadURL(rendererURL);
+    }
+    mainWindow.once("ready-to-show", async () => {
+        try {
+            splash.destroy();
+            if (!wasAutoLaunched) {
+                mainWindow.maximize();
+                mainWindow.show();
+            }
+        } catch (e) {
+            // ignore
+        }
+    });
+    mainWindow.webContents.on("render-process-gone", (event, details) => {
+        mainWindow.webContents.reload();
+        logErrorSentry(
+            Error("render-process-gone"),
+            "webContents event render-process-gone",
+            { details },
+        );
+        ElectronLog.log("webContents event render-process-gone", details);
+    });
+    mainWindow.webContents.on("unresponsive", () => {
+        mainWindow.webContents.forcefullyCrashRenderer();
+        ElectronLog.log("webContents event unresponsive");
+    });
+
+    setTimeout(() => {
+        try {
+            splash.destroy();
+            if (!wasAutoLaunched) {
+                mainWindow.maximize();
+                mainWindow.show();
+            }
+        } catch (e) {
+            // ignore
+        }
+    }, 2000);
+    mainWindow.on("close", function (event) {
+        if (!isAppQuitting()) {
+            event.preventDefault();
+            mainWindow.hide();
+        }
+        return false;
+    });
+    mainWindow.on("hide", () => {
+        const shouldHideDockIcon = getHideDockIconPreference();
+        if (isPlatform("mac") && shouldHideDockIcon) {
+            app.dock.hide();
+        }
+    });
+    mainWindow.on("show", () => {
+        if (isPlatform("mac")) {
+            app.dock.show();
+        }
+    });
+    return mainWindow;
+};
+
+/**
+ * Return the source root for the desktop code, i.e. the "desktop" directory in
+ * our repository which contains the package.json.
+ *
+ * This is useful to 
+ */
+const srcRoot = () => {
+        // __dirname will be the directory which contains this file. However, this
+    // file is not the one which is running - it'll get transpiled into JS, so
+    // the actual running file will be `app/main/init.js`. To get to the source
+    // root (the "desktop" folder), we need to go up two levels.
+
+}
+export async function handleUpdates(mainWindow: BrowserWindow) {
+    const isInstalledViaBrew = await checkIfInstalledViaBrew();
+    if (!isDev && !isInstalledViaBrew) {
+        setupAutoUpdater(mainWindow);
+    }
+}
+
+export const setupTrayItem = (mainWindow: BrowserWindow) => {
+    const iconName = isPlatform("mac")
+        ? "taskbar-icon-Template.png"
+        : "taskbar-icon.png";
+    const trayImgPath = path.join(
+        isDev ? "build" : process.resourcesPath,
+        iconName,
+    );
+    const trayIcon = nativeImage.createFromPath(trayImgPath);
+    const tray = new Tray(trayIcon);
+    tray.setToolTip("ente");
+    tray.setContextMenu(buildContextMenu(mainWindow));
+};
+
+export function handleDownloads(mainWindow: BrowserWindow) {
+    mainWindow.webContents.session.on("will-download", (_, item) => {
+        item.setSavePath(
+            getUniqueSavePath(item.getFilename(), app.getPath("downloads")),
+        );
+    });
+}
+
+export function handleExternalLinks(mainWindow: BrowserWindow) {
+    mainWindow.webContents.setWindowOpenHandler(({ url }) => {
+        if (!url.startsWith(rendererURL)) {
+            require("electron").shell.openExternal(url);
+            return { action: "deny" };
+        } else {
+            return { action: "allow" };
+        }
+    });
+}
+
+export function getUniqueSavePath(filename: string, directory: string): string {
+    let uniqueFileSavePath = path.join(directory, filename);
+    const { name: filenameWithoutExtension, ext: extension } =
+        path.parse(filename);
+    let n = 0;
+    while (existsSync(uniqueFileSavePath)) {
+        n++;
+        // filter need to remove undefined extension from the array
+        // else [`${fileName}`, undefined].join(".") will lead to `${fileName}.` as joined string
+        const fileNameWithNumberedSuffix = [
+            `${filenameWithoutExtension}(${n})`,
+            extension,
+        ]
+            .filter((x) => x) // filters out undefined/null values
+            .join("");
+        uniqueFileSavePath = path.join(directory, fileNameWithNumberedSuffix);
+    }
+    return uniqueFileSavePath;
+}
+
+export function setupMacWindowOnDockIconClick() {
+    app.on("activate", function () {
+        const windows = BrowserWindow.getAllWindows();
+        // we allow only one window
+        windows[0].show();
+    });
+}
+
+export async function setupMainMenu(mainWindow: BrowserWindow) {
+    Menu.setApplicationMenu(await buildMenuBar(mainWindow));
+}
+
+export async function handleDockIconHideOnAutoLaunch() {
+    const shouldHideDockIcon = getHideDockIconPreference();
+    const wasAutoLaunched = await autoLauncher.wasAutoLaunched();
+
+    if (isPlatform("mac") && shouldHideDockIcon && wasAutoLaunched) {
+        app.dock.hide();
+    }
+}
+
+export function logSystemInfo() {
+    const systemVersion = process.getSystemVersion();
+    const osName = process.platform;
+    const osRelease = os.release();
+    ElectronLog.info({ osName, osRelease, systemVersion });
+    const appVersion = app.getVersion();
+    ElectronLog.info({ appVersion });
+}
+
+export async function checkIfInstalledViaBrew() {
+    if (!isPlatform("mac")) {
+        return false;
+    }
+    try {
+        await execAsync("brew list --cask ente");
+        ElectronLog.info("ente installed via brew");
+        return true;
+    } catch (e) {
+        ElectronLog.info("ente not installed via brew");
+        return false;
+    }
+}
+
+function lowerCaseHeaders(responseHeaders: Record<string, string[]>) {
+    const headers: Record<string, string[]> = {};
+    for (const key of Object.keys(responseHeaders)) {
+        headers[key.toLowerCase()] = responseHeaders[key];
+    }
+    return headers;
+}
+
+export function addAllowOriginHeader(mainWindow: BrowserWindow) {
+    mainWindow.webContents.session.webRequest.onHeadersReceived(
+        (details, callback) => {
+            details.responseHeaders = lowerCaseHeaders(details.responseHeaders);
+            details.responseHeaders["access-control-allow-origin"] = ["*"];
+            callback({
+                responseHeaders: details.responseHeaders,
+            });
+        },
+    );
+}

+ 0 - 21
desktop/src/utils/cors.ts

@@ -1,21 +0,0 @@
-import { BrowserWindow } from "electron";
-
-function lowerCaseHeaders(responseHeaders: Record<string, string[]>) {
-    const headers: Record<string, string[]> = {};
-    for (const key of Object.keys(responseHeaders)) {
-        headers[key.toLowerCase()] = responseHeaders[key];
-    }
-    return headers;
-}
-
-export function addAllowOriginHeader(mainWindow: BrowserWindow) {
-    mainWindow.webContents.session.webRequest.onHeadersReceived(
-        (details, callback) => {
-            details.responseHeaders = lowerCaseHeaders(details.responseHeaders);
-            details.responseHeaders["access-control-allow-origin"] = ["*"];
-            callback({
-                responseHeaders: details.responseHeaders,
-            });
-        },
-    );
-}

+ 0 - 110
desktop/src/utils/createWindow.ts

@@ -1,110 +0,0 @@
-import { app, BrowserWindow, nativeImage } from "electron";
-import ElectronLog from "electron-log";
-import path from "path";
-import { isAppQuitting, rendererURL } from "../main";
-import { isDev } from "../main/general";
-import { logErrorSentry } from "../main/log";
-import autoLauncher from "../services/autoLauncher";
-import { getHideDockIconPreference } from "../services/userPreference";
-import { isPlatform } from "./common/platform";
-
-/**
- * Create an return the {@link BrowserWindow} that will form our app's UI.
- *
- * This window will show the HTML served from {@link rendererURL}.
- */
-export const createWindow = async () => {
-    const appImgPath = isDev
-        ? "resources/window-icon.png"
-        : path.join(process.resourcesPath, "window-icon.png");
-    const appIcon = nativeImage.createFromPath(appImgPath);
-    // Create the browser window.
-    const mainWindow = new BrowserWindow({
-        webPreferences: {
-            preload: path.join(__dirname, "../preload.js"),
-        },
-        icon: appIcon,
-        show: false, // don't show the main window on load,
-    });
-    const wasAutoLaunched = await autoLauncher.wasAutoLaunched();
-    ElectronLog.log("wasAutoLaunched", wasAutoLaunched);
-
-    const splash = new BrowserWindow({
-        transparent: true,
-        show: false,
-    });
-    if (isPlatform("mac") && wasAutoLaunched) {
-        app.dock.hide();
-    }
-    if (!wasAutoLaunched) {
-        splash.maximize();
-        splash.show();
-    }
-
-    if (isDev) {
-        splash.loadFile(`../resources/splash.html`);
-        mainWindow.loadURL(rendererURL);
-        // Open the DevTools.
-        mainWindow.webContents.openDevTools();
-    } else {
-        splash.loadURL(
-            `file://${path.join(process.resourcesPath, "splash.html")}`,
-        );
-        mainWindow.loadURL(rendererURL);
-    }
-    mainWindow.once("ready-to-show", async () => {
-        try {
-            splash.destroy();
-            if (!wasAutoLaunched) {
-                mainWindow.maximize();
-                mainWindow.show();
-            }
-        } catch (e) {
-            // ignore
-        }
-    });
-    mainWindow.webContents.on("render-process-gone", (event, details) => {
-        mainWindow.webContents.reload();
-        logErrorSentry(
-            Error("render-process-gone"),
-            "webContents event render-process-gone",
-            { details },
-        );
-        ElectronLog.log("webContents event render-process-gone", details);
-    });
-    mainWindow.webContents.on("unresponsive", () => {
-        mainWindow.webContents.forcefullyCrashRenderer();
-        ElectronLog.log("webContents event unresponsive");
-    });
-
-    setTimeout(() => {
-        try {
-            splash.destroy();
-            if (!wasAutoLaunched) {
-                mainWindow.maximize();
-                mainWindow.show();
-            }
-        } catch (e) {
-            // ignore
-        }
-    }, 2000);
-    mainWindow.on("close", function (event) {
-        if (!isAppQuitting()) {
-            event.preventDefault();
-            mainWindow.hide();
-        }
-        return false;
-    });
-    mainWindow.on("hide", () => {
-        const shouldHideDockIcon = getHideDockIconPreference();
-        if (isPlatform("mac") && shouldHideDockIcon) {
-            app.dock.hide();
-        }
-    });
-    mainWindow.on("show", () => {
-        if (isPlatform("mac")) {
-            app.dock.show();
-        }
-    });
-    return mainWindow;
-};

+ 0 - 118
desktop/src/utils/main.ts

@@ -1,118 +0,0 @@
-import { app, BrowserWindow, Menu, nativeImage, Tray } from "electron";
-import ElectronLog from "electron-log";
-import { existsSync } from "node:fs";
-import os from "os";
-import path from "path";
-import util from "util";
-import { rendererURL } from "../main";
-import { isDev } from "../main/general";
-import { setupAutoUpdater } from "../services/appUpdater";
-import autoLauncher from "../services/autoLauncher";
-import { getHideDockIconPreference } from "../services/userPreference";
-import { isPlatform } from "./common/platform";
-import { buildContextMenu, buildMenuBar } from "./menu";
-const execAsync = util.promisify(require("child_process").exec);
-
-export async function handleUpdates(mainWindow: BrowserWindow) {
-    const isInstalledViaBrew = await checkIfInstalledViaBrew();
-    if (!isDev && !isInstalledViaBrew) {
-        setupAutoUpdater(mainWindow);
-    }
-}
-
-export const setupTrayItem = (mainWindow: BrowserWindow) => {
-    const iconName = isPlatform("mac")
-        ? "taskbar-icon-Template.png"
-        : "taskbar-icon.png";
-    const trayImgPath = path.join(
-        isDev ? "build" : process.resourcesPath,
-        iconName,
-    );
-    const trayIcon = nativeImage.createFromPath(trayImgPath);
-    const tray = new Tray(trayIcon);
-    tray.setToolTip("ente");
-    tray.setContextMenu(buildContextMenu(mainWindow));
-};
-
-export function handleDownloads(mainWindow: BrowserWindow) {
-    mainWindow.webContents.session.on("will-download", (_, item) => {
-        item.setSavePath(
-            getUniqueSavePath(item.getFilename(), app.getPath("downloads")),
-        );
-    });
-}
-
-export function handleExternalLinks(mainWindow: BrowserWindow) {
-    mainWindow.webContents.setWindowOpenHandler(({ url }) => {
-        if (!url.startsWith(rendererURL)) {
-            require("electron").shell.openExternal(url);
-            return { action: "deny" };
-        } else {
-            return { action: "allow" };
-        }
-    });
-}
-
-export function getUniqueSavePath(filename: string, directory: string): string {
-    let uniqueFileSavePath = path.join(directory, filename);
-    const { name: filenameWithoutExtension, ext: extension } =
-        path.parse(filename);
-    let n = 0;
-    while (existsSync(uniqueFileSavePath)) {
-        n++;
-        // filter need to remove undefined extension from the array
-        // else [`${fileName}`, undefined].join(".") will lead to `${fileName}.` as joined string
-        const fileNameWithNumberedSuffix = [
-            `${filenameWithoutExtension}(${n})`,
-            extension,
-        ]
-            .filter((x) => x) // filters out undefined/null values
-            .join("");
-        uniqueFileSavePath = path.join(directory, fileNameWithNumberedSuffix);
-    }
-    return uniqueFileSavePath;
-}
-
-export function setupMacWindowOnDockIconClick() {
-    app.on("activate", function () {
-        const windows = BrowserWindow.getAllWindows();
-        // we allow only one window
-        windows[0].show();
-    });
-}
-
-export async function setupMainMenu(mainWindow: BrowserWindow) {
-    Menu.setApplicationMenu(await buildMenuBar(mainWindow));
-}
-
-export async function handleDockIconHideOnAutoLaunch() {
-    const shouldHideDockIcon = getHideDockIconPreference();
-    const wasAutoLaunched = await autoLauncher.wasAutoLaunched();
-
-    if (isPlatform("mac") && shouldHideDockIcon && wasAutoLaunched) {
-        app.dock.hide();
-    }
-}
-
-export function logSystemInfo() {
-    const systemVersion = process.getSystemVersion();
-    const osName = process.platform;
-    const osRelease = os.release();
-    ElectronLog.info({ osName, osRelease, systemVersion });
-    const appVersion = app.getVersion();
-    ElectronLog.info({ appVersion });
-}
-
-export async function checkIfInstalledViaBrew() {
-    if (!isPlatform("mac")) {
-        return false;
-    }
-    try {
-        await execAsync("brew list --cask ente");
-        ElectronLog.info("ente installed via brew");
-        return true;
-    } catch (e) {
-        ElectronLog.info("ente not installed via brew");
-        return false;
-    }
-}