this repo has no description
1import { webFrame, ipcRenderer, contextBridge } from "electron";
2import fs from "node:fs";
3import path from "node:path";
4
5import { readConfig, writeConfig } from "@moonlight-mod/core/config";
6import { constants, MoonlightBranch } from "@moonlight-mod/types";
7import { getExtensions } from "@moonlight-mod/core/extension";
8import {
9 getExtensionsPath,
10 getMoonlightDir
11} from "@moonlight-mod/core/util/data";
12import Logger, { initLogger } from "@moonlight-mod/core/util/logger";
13import {
14 loadExtensions,
15 loadProcessedExtensions
16} from "@moonlight-mod/core/extension/loader";
17import createFS from "@moonlight-mod/core/fs";
18
19async function injectGlobals() {
20 global.moonlightFS = createFS();
21
22 const config = await readConfig();
23 initLogger(config);
24 const extensions = await getExtensions();
25 const processedExtensions = await loadExtensions(extensions);
26 const moonlightDir = await getMoonlightDir();
27 const extensionsPath = await getExtensionsPath();
28
29 function getConfig(ext: string) {
30 const val = config.extensions[ext];
31 if (val == null || typeof val === "boolean") return undefined;
32 return val.config;
33 }
34
35 global.moonlightNode = {
36 config,
37 extensions,
38 processedExtensions,
39 nativesCache: {},
40 isBrowser: false,
41
42 version: MOONLIGHT_VERSION,
43 branch: MOONLIGHT_BRANCH as MoonlightBranch,
44
45 getConfig,
46 getConfigOption: <T>(ext: string, name: string) => {
47 const config = getConfig(ext);
48 if (config == null) return undefined;
49 const option = config[name];
50 if (option == null) return undefined;
51 return option as T;
52 },
53 getNatives: (ext: string) => global.moonlightNode.nativesCache[ext],
54 getLogger: (id: string) => {
55 return new Logger(id);
56 },
57
58 getMoonlightDir() {
59 return moonlightDir;
60 },
61 getExtensionDir: (ext: string) => {
62 return path.join(extensionsPath, ext);
63 },
64 writeConfig
65 };
66
67 await loadProcessedExtensions(processedExtensions);
68 contextBridge.exposeInMainWorld("moonlightNode", moonlightNode);
69
70 const extCors = moonlightNode.processedExtensions.extensions.flatMap(
71 (x) => x.manifest.cors ?? []
72 );
73
74 for (const repo of moonlightNode.config.repositories) {
75 const url = new URL(repo);
76 url.pathname = "/";
77 extCors.push(url.toString());
78 }
79
80 ipcRenderer.invoke(constants.ipcSetCorsList, extCors);
81
82 const extBlocked = moonlightNode.processedExtensions.extensions.flatMap(
83 (e) => e.manifest.blocked ?? []
84 );
85 ipcRenderer.invoke(constants.ipcSetBlockedList, extBlocked);
86}
87
88async function loadPreload() {
89 const webPreloadPath = path.join(__dirname, "web-preload.js");
90 const webPreload = fs.readFileSync(webPreloadPath, "utf8");
91 await webFrame.executeJavaScript(webPreload);
92}
93
94async function init(oldPreloadPath: string) {
95 try {
96 await injectGlobals();
97 await loadPreload();
98 } catch (e) {
99 const message = e instanceof Error ? e.stack : e;
100 await ipcRenderer.invoke(constants.ipcMessageBox, {
101 title: "moonlight node-preload error",
102 message: message
103 });
104 }
105
106 // Let Discord start even if we fail
107 if (oldPreloadPath) require(oldPreloadPath);
108}
109
110const oldPreloadPath: string = ipcRenderer.sendSync(
111 constants.ipcGetOldPreloadPath
112);
113init(oldPreloadPath);