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