-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: main electron with managers and handlers
- Loading branch information
Showing
13 changed files
with
588 additions
and
430 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { app, ipcMain, shell } from "electron"; | ||
import { ModuleManager } from "../managers/module"; | ||
import { join } from "path"; | ||
import { PluginManager } from "../managers/plugin"; | ||
import { WindowManager } from "../managers/window"; | ||
|
||
export function handleAppIPCs() { | ||
/** | ||
* Retrieves the path to the app data directory using the `coreAPI` object. | ||
* If the `coreAPI` object is not available, the function returns `undefined`. | ||
* @returns A Promise that resolves with the path to the app data directory, or `undefined` if the `coreAPI` object is not available. | ||
*/ | ||
ipcMain.handle("appDataPath", async (_event) => { | ||
return app.getPath("userData"); | ||
}); | ||
|
||
/** | ||
* Returns the version of the app. | ||
* @param _event - The IPC event object. | ||
* @returns The version of the app. | ||
*/ | ||
ipcMain.handle("appVersion", async (_event) => { | ||
return app.getVersion(); | ||
}); | ||
|
||
/** | ||
* Handles the "openAppDirectory" IPC message by opening the app's user data directory. | ||
* The `shell.openPath` method is used to open the directory in the user's default file explorer. | ||
* @param _event - The IPC event object. | ||
*/ | ||
ipcMain.handle("openAppDirectory", async (_event) => { | ||
shell.openPath(app.getPath("userData")); | ||
}); | ||
|
||
/** | ||
* Opens a URL in the user's default browser. | ||
* @param _event - The IPC event object. | ||
* @param url - The URL to open. | ||
*/ | ||
ipcMain.handle("openExternalUrl", async (_event, url) => { | ||
shell.openExternal(url); | ||
}); | ||
|
||
/** | ||
* Relaunches the app in production - reload window in development. | ||
* @param _event - The IPC event object. | ||
* @param url - The URL to reload. | ||
*/ | ||
ipcMain.handle("relaunch", async (_event, url) => { | ||
ModuleManager.instance.clearImportedModules(); | ||
|
||
if (app.isPackaged) { | ||
app.relaunch(); | ||
app.exit(); | ||
} else { | ||
for (const modulePath in ModuleManager.instance.requiredModules) { | ||
delete require.cache[ | ||
require.resolve(join(app.getPath("userData"), "plugins", modulePath)) | ||
]; | ||
} | ||
PluginManager.instance.setupPlugins(); | ||
WindowManager.instance.currentWindow?.reload(); | ||
} | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { app, ipcMain } from "electron"; | ||
import { DownloadManager } from "../managers/download"; | ||
import { resolve, join } from "path"; | ||
import { WindowManager } from "../managers/window"; | ||
import request from "request"; | ||
import { createWriteStream, unlink } from "fs"; | ||
const progress = require("request-progress"); | ||
|
||
export function handleDownloaderIPCs() { | ||
/** | ||
* Handles the "pauseDownload" IPC message by pausing the download associated with the provided fileName. | ||
* @param _event - The IPC event object. | ||
* @param fileName - The name of the file being downloaded. | ||
*/ | ||
ipcMain.handle("pauseDownload", async (_event, fileName) => { | ||
DownloadManager.instance.networkRequests[fileName]?.pause(); | ||
}); | ||
|
||
/** | ||
* Handles the "resumeDownload" IPC message by resuming the download associated with the provided fileName. | ||
* @param _event - The IPC event object. | ||
* @param fileName - The name of the file being downloaded. | ||
*/ | ||
ipcMain.handle("resumeDownload", async (_event, fileName) => { | ||
DownloadManager.instance.networkRequests[fileName]?.resume(); | ||
}); | ||
|
||
/** | ||
* Handles the "abortDownload" IPC message by aborting the download associated with the provided fileName. | ||
* The network request associated with the fileName is then removed from the networkRequests object. | ||
* @param _event - The IPC event object. | ||
* @param fileName - The name of the file being downloaded. | ||
*/ | ||
ipcMain.handle("abortDownload", async (_event, fileName) => { | ||
const rq = DownloadManager.instance.networkRequests[fileName]; | ||
DownloadManager.instance.networkRequests[fileName] = undefined; | ||
const userDataPath = app.getPath("userData"); | ||
const fullPath = join(userDataPath, fileName); | ||
rq?.abort(); | ||
let result = "NULL"; | ||
unlink(fullPath, function (err) { | ||
if (err && err.code == "ENOENT") { | ||
result = `File not exist: ${err}`; | ||
} else if (err) { | ||
result = `File delete error: ${err}`; | ||
} else { | ||
result = "File deleted successfully"; | ||
} | ||
console.log(`Delete file ${fileName} from ${fullPath} result: ${result}`); | ||
}); | ||
}); | ||
|
||
/** | ||
* Downloads a file from a given URL. | ||
* @param _event - The IPC event object. | ||
* @param url - The URL to download the file from. | ||
* @param fileName - The name to give the downloaded file. | ||
*/ | ||
ipcMain.handle("downloadFile", async (_event, url, fileName) => { | ||
const userDataPath = app.getPath("userData"); | ||
const destination = resolve(userDataPath, fileName); | ||
const rq = request(url); | ||
|
||
progress(rq, {}) | ||
.on("progress", function (state: any) { | ||
WindowManager?.instance.currentWindow?.webContents.send( | ||
"FILE_DOWNLOAD_UPDATE", | ||
{ | ||
...state, | ||
fileName, | ||
} | ||
); | ||
}) | ||
.on("error", function (err: Error) { | ||
WindowManager?.instance.currentWindow?.webContents.send( | ||
"FILE_DOWNLOAD_ERROR", | ||
{ | ||
fileName, | ||
err, | ||
} | ||
); | ||
}) | ||
.on("end", function () { | ||
if (DownloadManager.instance.networkRequests[fileName]) { | ||
WindowManager?.instance.currentWindow?.webContents.send( | ||
"FILE_DOWNLOAD_COMPLETE", | ||
{ | ||
fileName, | ||
} | ||
); | ||
DownloadManager.instance.setRequest(fileName, undefined); | ||
} else { | ||
WindowManager?.instance.currentWindow?.webContents.send( | ||
"FILE_DOWNLOAD_ERROR", | ||
{ | ||
fileName, | ||
err: "Download cancelled", | ||
} | ||
); | ||
} | ||
}) | ||
.pipe(createWriteStream(destination)); | ||
|
||
DownloadManager.instance.setRequest(fileName, rq); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { app, ipcMain } from "electron"; | ||
import { readdirSync, rmdir, writeFileSync } from "fs"; | ||
import { ModuleManager } from "../managers/module"; | ||
import { join, extname } from "path"; | ||
import { PluginManager } from "../managers/plugin"; | ||
import { WindowManager } from "../managers/window"; | ||
const pacote = require("pacote"); | ||
|
||
export function handlePluginIPCs() { | ||
/** | ||
* Invokes a function from a plugin module in main node process. | ||
* @param _event - The IPC event object. | ||
* @param modulePath - The path to the plugin module. | ||
* @param method - The name of the function to invoke. | ||
* @param args - The arguments to pass to the function. | ||
* @returns The result of the invoked function. | ||
*/ | ||
ipcMain.handle( | ||
"invokePluginFunc", | ||
async (_event, modulePath, method, ...args) => { | ||
const module = require( | ||
/* webpackIgnore: true */ join( | ||
app.getPath("userData"), | ||
"plugins", | ||
modulePath | ||
) | ||
); | ||
ModuleManager.instance.setModule(modulePath, module); | ||
|
||
if (typeof module[method] === "function") { | ||
return module[method](...args); | ||
} else { | ||
console.log(module[method]); | ||
console.error(`Function "${method}" does not exist in the module.`); | ||
} | ||
} | ||
); | ||
|
||
/** | ||
* Returns the paths of the base plugins. | ||
* @param _event - The IPC event object. | ||
* @returns An array of paths to the base plugins. | ||
*/ | ||
ipcMain.handle("basePlugins", async (_event) => { | ||
const basePluginPath = join( | ||
__dirname, | ||
"../", | ||
app.isPackaged | ||
? "../../app.asar.unpacked/core/pre-install" | ||
: "../core/pre-install" | ||
); | ||
return readdirSync(basePluginPath) | ||
.filter((file) => extname(file) === ".tgz") | ||
.map((file) => join(basePluginPath, file)); | ||
}); | ||
|
||
/** | ||
* Returns the path to the user's plugin directory. | ||
* @param _event - The IPC event object. | ||
* @returns The path to the user's plugin directory. | ||
*/ | ||
ipcMain.handle("pluginPath", async (_event) => { | ||
return join(app.getPath("userData"), "plugins"); | ||
}); | ||
|
||
/** | ||
* Deletes the `plugins` directory in the user data path and disposes of required modules. | ||
* If the app is packaged, the function relaunches the app and exits. | ||
* Otherwise, the function deletes the cached modules and sets up the plugins and reloads the main window. | ||
* @param _event - The IPC event object. | ||
* @param url - The URL to reload. | ||
*/ | ||
ipcMain.handle("reloadPlugins", async (_event, url) => { | ||
const userDataPath = app.getPath("userData"); | ||
const fullPath = join(userDataPath, "plugins"); | ||
|
||
rmdir(fullPath, { recursive: true }, function (err) { | ||
if (err) console.log(err); | ||
ModuleManager.instance.clearImportedModules(); | ||
|
||
// just relaunch if packaged, should launch manually in development mode | ||
if (app.isPackaged) { | ||
app.relaunch(); | ||
app.exit(); | ||
} else { | ||
for (const modulePath in ModuleManager.instance.requiredModules) { | ||
delete require.cache[ | ||
require.resolve( | ||
join(app.getPath("userData"), "plugins", modulePath) | ||
) | ||
]; | ||
} | ||
PluginManager.instance.setupPlugins(); | ||
WindowManager.instance.currentWindow?.reload(); | ||
} | ||
}); | ||
}); | ||
|
||
/** | ||
* Installs a remote plugin by downloading its tarball and writing it to a tgz file. | ||
* @param _event - The IPC event object. | ||
* @param pluginName - The name of the remote plugin to install. | ||
* @returns A Promise that resolves to the path of the installed plugin file. | ||
*/ | ||
ipcMain.handle("installRemotePlugin", async (_event, pluginName) => { | ||
const destination = join( | ||
app.getPath("userData"), | ||
pluginName.replace(/^@.*\//, "") + ".tgz" | ||
); | ||
return pacote | ||
.manifest(pluginName) | ||
.then(async (manifest: any) => { | ||
await pacote.tarball(manifest._resolved).then((data: Buffer) => { | ||
writeFileSync(destination, data); | ||
}); | ||
}) | ||
.then(() => destination); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { ipcMain, nativeTheme } from "electron"; | ||
|
||
export function handleThemesIPCs() { | ||
/** | ||
* Handles the "setNativeThemeLight" IPC message by setting the native theme source to "light". | ||
* This will change the appearance of the app to the light theme. | ||
*/ | ||
ipcMain.handle("setNativeThemeLight", () => { | ||
nativeTheme.themeSource = "light"; | ||
}); | ||
|
||
/** | ||
* Handles the "setNativeThemeDark" IPC message by setting the native theme source to "dark". | ||
* This will change the appearance of the app to the dark theme. | ||
*/ | ||
ipcMain.handle("setNativeThemeDark", () => { | ||
nativeTheme.themeSource = "dark"; | ||
}); | ||
|
||
/** | ||
* Handles the "setNativeThemeSystem" IPC message by setting the native theme source to "system". | ||
* This will change the appearance of the app to match the system's current theme. | ||
*/ | ||
ipcMain.handle("setNativeThemeSystem", () => { | ||
nativeTheme.themeSource = "system"; | ||
}); | ||
} |
Oops, something went wrong.