this repo has no description
at v1.2.4 6.5 kB view raw
1import { MoonlightBranch } from "@moonlight-mod/types"; 2import type { MoonbaseNatives, RepositoryManifest } from "./types"; 3import extractAsar from "@moonlight-mod/core/asar"; 4import { distDir, repoUrlFile, installedVersionFile } from "@moonlight-mod/types/constants"; 5import { parseTarGzip } from "nanotar"; 6 7const githubRepo = "moonlight-mod/moonlight"; 8const githubApiUrl = `https://api.github.com/repos/${githubRepo}/releases/latest`; 9const artifactName = "dist.tar.gz"; 10 11const nightlyRefUrl = "https://moonlight-mod.github.io/moonlight/ref"; 12const nightlyZipUrl = "https://moonlight-mod.github.io/moonlight/dist.tar.gz"; 13 14export const userAgent = `moonlight/${moonlightNode.version} (https://github.com/moonlight-mod/moonlight)`; 15 16async function getStableRelease(): Promise<{ 17 name: string; 18 assets: { 19 name: string; 20 browser_download_url: string; 21 }[]; 22}> { 23 const req = await fetch(githubApiUrl, { 24 cache: "no-store", 25 headers: { 26 "User-Agent": userAgent 27 } 28 }); 29 return await req.json(); 30} 31 32export default function getNatives(): MoonbaseNatives { 33 const logger = moonlightNode.getLogger("moonbase/natives"); 34 35 return { 36 async checkForMoonlightUpdate() { 37 try { 38 if (moonlightNode.branch === MoonlightBranch.STABLE) { 39 const json = await getStableRelease(); 40 return json.name !== moonlightNode.version ? json.name : null; 41 } else if (moonlightNode.branch === MoonlightBranch.NIGHTLY) { 42 const req = await fetch(nightlyRefUrl, { 43 cache: "no-store", 44 headers: { 45 "User-Agent": userAgent 46 } 47 }); 48 const ref = (await req.text()).split("\n")[0]; 49 return ref !== moonlightNode.version ? ref : null; 50 } 51 52 return null; 53 } catch (e) { 54 logger.error("Error checking for moonlight update", e); 55 return null; 56 } 57 }, 58 59 async updateMoonlight() { 60 // Note: this won't do anything on browser, we should probably disable it 61 // entirely when running in browser. 62 async function downloadStable(): Promise<[ArrayBuffer, string]> { 63 const json = await getStableRelease(); 64 const asset = json.assets.find((a) => a.name === artifactName); 65 if (!asset) throw new Error("Artifact not found"); 66 67 logger.debug(`Downloading ${asset.browser_download_url}`); 68 const req = await fetch(asset.browser_download_url, { 69 cache: "no-store", 70 headers: { 71 "User-Agent": userAgent 72 } 73 }); 74 75 return [await req.arrayBuffer(), json.name]; 76 } 77 78 async function downloadNightly(): Promise<[ArrayBuffer, string]> { 79 logger.debug(`Downloading ${nightlyZipUrl}`); 80 const zipReq = await fetch(nightlyZipUrl, { 81 cache: "no-store", 82 headers: { 83 "User-Agent": userAgent 84 } 85 }); 86 87 const refReq = await fetch(nightlyRefUrl, { 88 cache: "no-store", 89 headers: { 90 "User-Agent": userAgent 91 } 92 }); 93 const ref = (await refReq.text()).split("\n")[0]; 94 95 return [await zipReq.arrayBuffer(), ref]; 96 } 97 98 const [tar, ref] = 99 moonlightNode.branch === MoonlightBranch.STABLE 100 ? await downloadStable() 101 : moonlightNode.branch === MoonlightBranch.NIGHTLY 102 ? await downloadNightly() 103 : [null, null]; 104 105 if (!tar || !ref) return; 106 107 const dist = moonlightNodeSandboxed.fs.join(moonlightNode.getMoonlightDir(), distDir); 108 if (await moonlightNodeSandboxed.fs.exists(dist)) await moonlightNodeSandboxed.fs.rmdir(dist); 109 await moonlightNodeSandboxed.fs.mkdir(dist); 110 111 logger.debug("Extracting update"); 112 const files = await parseTarGzip(tar); 113 for (const file of files) { 114 if (!file.data) continue; 115 // @ts-expect-error What do you mean their own types are wrong 116 if (file.type !== "file") continue; 117 118 const fullFile = moonlightNodeSandboxed.fs.join(dist, file.name); 119 const fullDir = moonlightNodeSandboxed.fs.dirname(fullFile); 120 if (!(await moonlightNodeSandboxed.fs.exists(fullDir))) await moonlightNodeSandboxed.fs.mkdir(fullDir); 121 await moonlightNodeSandboxed.fs.writeFile(fullFile, file.data); 122 } 123 124 logger.debug("Writing version file:", ref); 125 const versionFile = moonlightNodeSandboxed.fs.join(moonlightNode.getMoonlightDir(), installedVersionFile); 126 await moonlightNodeSandboxed.fs.writeFileString(versionFile, ref.trim()); 127 128 logger.debug("Update extracted"); 129 }, 130 131 async fetchRepositories(repos) { 132 const ret: Record<string, RepositoryManifest[]> = {}; 133 134 for (const repo of repos) { 135 try { 136 const req = await fetch(repo, { 137 cache: "no-store", 138 headers: { 139 "User-Agent": userAgent 140 } 141 }); 142 const json = await req.json(); 143 ret[repo] = json; 144 } catch (e) { 145 logger.error(`Error fetching repository ${repo}`, e); 146 } 147 } 148 149 return ret; 150 }, 151 152 async installExtension(manifest, url, repo) { 153 const req = await fetch(url, { 154 cache: "no-store", 155 headers: { 156 "User-Agent": userAgent 157 } 158 }); 159 160 const dir = moonlightNode.getExtensionDir(manifest.id); 161 // remake it in case of updates 162 if (await moonlightNodeSandboxed.fs.exists(dir)) await moonlightNodeSandboxed.fs.rmdir(dir); 163 await moonlightNodeSandboxed.fs.mkdir(dir); 164 165 const buffer = await req.arrayBuffer(); 166 const files = extractAsar(buffer); 167 for (const [file, buf] of Object.entries(files)) { 168 const fullFile = moonlightNodeSandboxed.fs.join(dir, file); 169 const fullDir = moonlightNodeSandboxed.fs.dirname(fullFile); 170 171 if (!(await moonlightNodeSandboxed.fs.exists(fullDir))) await moonlightNodeSandboxed.fs.mkdir(fullDir); 172 await moonlightNodeSandboxed.fs.writeFile(moonlightNodeSandboxed.fs.join(dir, file), buf); 173 } 174 175 await moonlightNodeSandboxed.fs.writeFileString(moonlightNodeSandboxed.fs.join(dir, repoUrlFile), repo); 176 }, 177 178 async deleteExtension(id) { 179 const dir = moonlightNode.getExtensionDir(id); 180 await moonlightNodeSandboxed.fs.rmdir(dir); 181 }, 182 183 getExtensionConfig(id, key) { 184 const config = moonlightNode.config.extensions[id]; 185 if (typeof config === "object") { 186 return config.config?.[key]; 187 } 188 189 return undefined; 190 } 191 }; 192}