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