157 lines
4.4 kB
1
import "@moonlight-mod/web-preload";
2
import { readConfig, writeConfig } from "@moonlight-mod/core/config";
3
import Logger, { initLogger } from "@moonlight-mod/core/util/logger";
4
import { getExtensions } from "@moonlight-mod/core/extension";
5
import { loadExtensions } from "@moonlight-mod/core/extension/loader";
6
import { MoonlightBranch, MoonlightNode } from "@moonlight-mod/types";
7
import { getConfig, getConfigOption, getManifest, setConfigOption } from "@moonlight-mod/core/util/config";
8
import { IndexedDB } from "@zenfs/dom";
9
import { configureSingle } from "@zenfs/core";
10
import * as fs from "@zenfs/core/promises";
11
import { NodeEventPayloads, NodeEventType } from "@moonlight-mod/types/core/event";
12
import { createEventEmitter } from "@moonlight-mod/core/util/event";
13
14
function getParts(path: string) {
15
if (path.startsWith("/")) path = path.substring(1);
16
return path.split("/");
17
}
18
19
window._moonlightBrowserInit = async () => {
20
delete window._moonlightBrowserInit;
21
22
// Set up a virtual filesystem with IndexedDB
23
await configureSingle({
24
backend: IndexedDB,
25
storeName: "moonlight-fs"
26
});
27
28
window.moonlightNodeSandboxed = {
29
fs: {
30
async readFile(path) {
31
return new Uint8Array(await fs.readFile(path));
32
},
33
async readFileString(path) {
34
const file = await this.readFile(path);
35
return new TextDecoder().decode(file);
36
},
37
async writeFile(path, data) {
38
await fs.writeFile(path, data);
39
},
40
async writeFileString(path, data) {
41
const file = new TextEncoder().encode(data);
42
await this.writeFile(path, file);
43
},
44
async unlink(path) {
45
await fs.unlink(path);
46
},
47
48
async readdir(path) {
49
return await fs.readdir(path);
50
},
51
async mkdir(path) {
52
const parts = getParts(path);
53
for (let i = 0; i < parts.length; i++) {
54
const path = this.join(...parts.slice(0, i + 1));
55
if (!(await this.exists(path))) await fs.mkdir(path);
56
}
57
},
58
59
async rmdir(path) {
60
const entries = await this.readdir(path);
61
62
for (const entry of entries) {
63
const fullPath = this.join(path, entry);
64
const isFile = await this.isFile(fullPath);
65
if (isFile) {
66
await this.unlink(fullPath);
67
} else {
68
await this.rmdir(fullPath);
69
}
70
}
71
72
await fs.rmdir(path);
73
},
74
75
async exists(path) {
76
return await fs.exists(path);
77
},
78
async isFile(path) {
79
return (await fs.stat(path)).isFile();
80
},
81
async isDir(path) {
82
return (await fs.stat(path)).isDirectory();
83
},
84
85
join(...parts) {
86
let str = parts.join("/");
87
if (!str.startsWith("/")) str = "/" + str;
88
return str;
89
},
90
dirname(path) {
91
const parts = getParts(path);
92
return "/" + parts.slice(0, parts.length - 1).join("/");
93
}
94
},
95
// TODO
96
addCors(url) {},
97
addBlocked(url) {}
98
};
99
100
// Actual loading begins here
101
let config = await readConfig();
102
initLogger(config);
103
104
const extensions = await getExtensions();
105
const processedExtensions = await loadExtensions(extensions);
106
107
const moonlightNode: MoonlightNode = {
108
get config() {
109
return config;
110
},
111
extensions,
112
processedExtensions,
113
nativesCache: {},
114
isBrowser: true,
115
events: createEventEmitter<NodeEventType, NodeEventPayloads>(),
116
117
version: MOONLIGHT_VERSION,
118
branch: MOONLIGHT_BRANCH as MoonlightBranch,
119
120
getConfig(ext) {
121
return getConfig(ext, config);
122
},
123
getConfigOption(ext, name) {
124
const manifest = getManifest(extensions, ext);
125
return getConfigOption(ext, name, config, manifest?.settings);
126
},
127
async setConfigOption(ext, name, value) {
128
setConfigOption(config, ext, name, value);
129
await this.writeConfig(config);
130
},
131
132
getNatives: () => {},
133
getLogger: (id: string) => {
134
return new Logger(id);
135
},
136
137
getMoonlightDir() {
138
return "/";
139
},
140
getExtensionDir: (ext: string) => {
141
return `/extensions/${ext}`;
142
},
143
144
async writeConfig(newConfig) {
145
await writeConfig(newConfig);
146
config = newConfig;
147
this.events.dispatchEvent(NodeEventType.ConfigSaved, newConfig);
148
}
149
};
150
151
Object.assign(window, {
152
moonlightNode
153
});
154
155
// This is set by web-preload for us
156
await window._moonlightWebLoad!();
157
};
158