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